home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-1.iso / comm / slip_new.zip / UMSLIP.ASM < prev    next >
Assembly Source File  |  1995-07-10  |  88KB  |  3,548 lines

  1. ;  Copyright, 1988-1992, Russell Nelson, Crynwr Software
  2.  
  3. ;   This program is free software; you can redistribute it and/or modify
  4. ;   it under the terms of the GNU General MakePublic License as published by
  5. ;   the Free Software Foundation, version 1.
  6. ;
  7. ;   This program is distributed in the hope that it will be useful,
  8. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10. ;   GNU General MakePublic License for more details.
  11. ;
  12. ;   You should have received a copy of the GNU General MakePublic License
  13. ;   along with this program; if not, write to the Free Software
  14. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ;
  16. ;
  17. ;
  18. ;
  19. ;   Copyright 1993, University of Minnesota
  20. ;
  21. ;   Changes at U of M:     (slip@booombox.micro.umn.edu)
  22. ;
  23. ;   Changed many things to make it possible to set serial parameters
  24. ;   on the fly.
  25. ;   Fixed many timing problems.
  26. ;   Added output handshaking.
  27. ;   Cleaned up loop timing code.
  28. ;   Made all opens delayed.
  29. ;   Configuration is done by another program (PHONE.EXE)
  30. ;
  31. ;   Still need to:
  32. ;   Compute correct timing delays.
  33. ;   Add input handshaking.
  34. ;   Timeout hung handshaking properly.
  35. ;   38,400 baud loses a few characters.
  36. ;   Doesnt detect missing com port.
  37. ;
  38.  
  39.  
  40. majver        equ    1        ;version number of the infrastructure.
  41.  
  42. MAX_ADDR_LEN    equ    16        ;maximum number of bytes in our address.
  43.  
  44. MAX_HANDLE    equ    10        ;maximum number of handles.
  45.  
  46. MAX_P_LEN    equ    8        ;maximum type length
  47.  
  48. MAX_MULTICAST    equ    8        ;maximum number of multicast addresses.
  49.  
  50.  
  51. HT    equ    09h
  52. CR    equ    0dh
  53. LF    equ    0ah
  54.  
  55. ;
  56. ;  Packet Driver Error numbers
  57. NO_ERROR    equ    0        ;no error at all.
  58. BAD_HANDLE    equ    1        ;invalid handle number
  59. NO_CLASS    equ    2        ;no interfaces of specified class found
  60. NO_TYPE        equ    3        ;no interfaces of specified type found
  61. NO_NUMBER    equ    4        ;no interfaces of specified number found
  62. BAD_TYPE    equ    5        ;bad packet type specified
  63. NO_MULTICAST    equ    6        ;this interface does not support
  64.                     ;multicast
  65. CANT_TERMINATE    equ    7        ;this packet driver cannot terminate
  66. BAD_MODE    equ    8        ;an invalid receiver mode was specified
  67. NO_SPACE    equ    9        ;operation failed because of
  68.                     ;insufficient space
  69. TYPE_INUSE    equ    10        ;the type had previously been accessed,
  70.                     ;and not released.
  71. BAD_COMMAND    equ    11        ;the command was out of range, or not
  72.                     ;implemented
  73. CANT_SEND    equ    12        ;the packet couldn't be sent (usually
  74.                     ;hardware error)
  75. CANT_SET    equ    13        ;hardware address couldn't be changed
  76.                     ;(more than 1 handle open)
  77. BAD_ADDRESS    equ    14        ;hardware address has bad length or
  78.                     ;format
  79. CANT_RESET    equ    15        ;Couldn't reset interface (more than
  80.                     ;1 handle open).
  81. BAD_IOCB    equ    16        ;an invalid iocb was specified
  82.  
  83. ;a few useful Ethernet definitions.
  84. RUNT        equ    60        ;smallest legal size packet, no fcs
  85. GIANT        equ    1514        ;largest legal size packet, no fcs
  86. EADDR_LEN    equ    6        ;Ethernet address length.
  87. ARCADDR_LEN    equ    1
  88.  
  89. BLUEBOOK    equ    1
  90. IEEE8023    equ    11
  91.  
  92.  
  93.  
  94.  
  95. MakePublic      macro   Sym
  96. ;;;             Public  &Sym            ; no publics now...
  97.                 endm
  98.  
  99. MakeExternal    macro   Sym
  100. ;;;             Extrn   &Sym            ; no externs now...
  101.                 endm
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110. ;The following two macros are used to manipulate port addresses.
  111. ;Use loadport to initialize dx.  Use setport to set a specific port on
  112. ;the board.  setport remembers what the current port number is, but beware!
  113. ;setport assumes that code is being executed in the same order as the
  114. ;code is presented in the source file.  Whenever this assumption is violated,
  115. ;you need to enter another loadport.  Some, but not all examples are:
  116. ;in a loop with multiple setports, or a backward jump over a setport, or
  117. ;a forward jump over a setport.  If you have any doubt, consult the
  118. ;individual driver sources for examples of usage.  If you suspect that
  119. ;you have too few loadports, define the symbol "no_confidence" to a
  120. ;one.  This will force a loadport before every setport.  If you wish to turn
  121. ;it off for some of your code, redefine it to a zero.
  122.  
  123. loadport    macro
  124.     mov    dx,io_addr
  125. port_no    =    0
  126.     endm
  127.  
  128. ;change the port number from the current value to the new value.
  129. setport    macro    new_port_no
  130.     ifdef    no_confidence        ;define if you suspect that you don't
  131.       if    no_confidence
  132.         loadport        ;  have enough loadports, i.e. dx is
  133.       endif
  134.     endif                ;  set to the wrong port.
  135.     if    new_port_no - port_no EQ 1
  136.         inc    dx
  137.     else
  138.         if    new_port_no - port_no EQ -1
  139.             dec    dx
  140.         else
  141.             if    new_port_no - port_no NE 0
  142.                 add    dx,new_port_no - port_no
  143.             endif
  144.         endif
  145.     endif
  146. port_no    =    new_port_no
  147.     endm
  148.  
  149. Print    macro
  150.     call    DosPrint
  151.         endm
  152.  
  153. Delay           Macro
  154.                 call  DelaySub
  155.                 endm
  156.  
  157.  
  158.  
  159. SlowIn    macro
  160.     Delay
  161.         in    al,dx
  162.         endm
  163.  
  164.  
  165. SlowOut    macro
  166.     Delay
  167.         out    dx,al
  168.         endm
  169.  
  170.  
  171. segmoffs    struc            ; defines offs as 0, segm as 2
  172. offs        dw    ?
  173. segm        dw    ?
  174. segmoffs    ends
  175.  
  176. CY    equ    0001h
  177. EI    equ    0200h
  178.  
  179. iocb        struc            ; as_send_pkt structure
  180. buffer        dd    ?        ; Pointer to the buffer
  181. len        dw    ?        ; Its length
  182. flags        db    ?        ; Some flags
  183. ret_code    db    ?        ; Completion code
  184. upcall        dd    ?        ; I/O completion upcall
  185. next        dd    ?        ; Private next pointer (queue)
  186. resv        db    4 dup (?)    ; Unused private data
  187. iocb        ends
  188.  
  189. DONE    equ    1        ; I/O complete flag
  190. CALLME    equ    2        ; Please upcall me flag
  191.  
  192.  
  193. send_queueempty    macro
  194. ; Check if send queue is empty.
  195. ; Enter with interrupts disabled.
  196. ; Exit with zr (zero) if empty, nz (not zero) if not.
  197. ; Destroys ax.
  198.     mov ax,    word ptr send_head    ; Queue empty?
  199.     or ax,    word ptr send_head+2
  200.     endm
  201.  
  202. send_peekqueue    macro
  203. ; Peek into the queue and get the next entry.
  204. ; Enter with interrupts disabled.
  205. ; Exit with es:di -> iocb.
  206.     les di, send_head    ; Get head segment:offset
  207.     endm
  208.  
  209. ; Bits in sys_features
  210. MICROCHANNEL    equ    02        ; a micro channel computer
  211. TWO_8259    equ    40h        ; 2nd 8259 exists
  212.  
  213. ; Bits in flagbyte
  214. CALLED_ETOPEN    equ    1        ; have called etopen
  215. D_OPTION    equ    2        ; delayed initialization
  216. N_OPTION    equ    4        ; Novell protocol conversion
  217. W_OPTION    equ    8        ; Windows upcall checking.
  218.  
  219. ;  Copyright, 1988-1992, Russell Nelson, Crynwr Software
  220.  
  221. ;   This program is free software; you can redistribute it and/or modify
  222. ;   it under the terms of the GNU General MakePublic License as published by
  223. ;   the Free Software Foundation, version 1.
  224. ;
  225. ;   This program is distributed in the hope that it will be useful,
  226. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  227. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  228. ;   GNU General MakePublic License for more details.
  229. ;
  230. ;   You should have received a copy of the GNU General MakePublic License
  231. ;   along with this program; if not, write to the Free Software
  232. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  233.  
  234.  
  235.  
  236. code    segment word
  237.     assume    cs:code, ds:code
  238.  
  239.     MakePublic    phd_environ
  240.     org    2ch
  241. phd_environ    dw    ?
  242.  
  243.     MakePublic    phd_dioa
  244.     org    80h
  245. phd_dioa    label    byte
  246.  
  247.     org    100h
  248. start:
  249.     jmp    start_1
  250.     MakeExternal    start_1: near
  251.     even                ;put the stack on a word boundary.
  252.  
  253. ;we use our dioa for a stack space.  Very hard usage has shown that only
  254. ;  27 bytes were being used, so 128 should be sufficient.
  255. our_stack    label    byte
  256.  
  257.  
  258.     MakeExternal    int_no: byte
  259.     MakePublic    packet_int_no, is_at, sys_features, flagbyte,quiet
  260.  
  261. packet_int_no    db    60h,0,0,0    ; interrupt to communicate.
  262. is_at        db    0        ; =1 if we're on an AT.
  263. sys_features    db    0        ; 2h = MC   40h = 2nd 8259
  264. flagbyte    db    0
  265. quiet        db    0
  266.  
  267.     even
  268.  
  269. functions    label    word
  270.     dw    f_not_implemented    ;0
  271.     dw    f_driver_info        ;1
  272.     dw    f_access_type        ;2
  273.     dw    f_release_type        ;3
  274.     dw    f_send_pkt        ;4
  275.     dw    f_terminate        ;5
  276.     dw    f_get_address        ;6
  277.     dw    f_reset_interface    ;7
  278.     dw    f_stop            ;8
  279.     dw    f_not_implemented    ;9
  280.     dw    f_get_parameters    ;10
  281.     dw    f_not_implemented    ;11
  282.     dw    f_as_send_pkt        ;12
  283.     dw    f_drop_pkt        ;13
  284.     dw    f_ser_func        ;14
  285.     dw    f_not_implemented    ;15
  286.     dw    f_not_implemented    ;16
  287.     dw    f_not_implemented    ;17
  288.     dw    f_not_implemented    ;18
  289.     dw    f_not_implemented    ;19
  290.     dw    f_set_rcv_mode        ;20
  291.     dw    f_get_rcv_mode        ;21
  292.     dw    f_set_multicast_list    ;22
  293.     dw    f_get_multicast_list    ;23
  294.     dw    f_get_statistics    ;24
  295.     dw    f_set_address        ;25
  296.  
  297.     MakeExternal    driver_class: byte
  298.     MakeExternal    driver_type: byte
  299.     MakeExternal    driver_name: byte
  300.     MakeExternal    driver_function: byte
  301.     MakeExternal    parameter_list: byte
  302.  
  303.     MakeExternal    send_pkt: near
  304.     MakeExternal    as_send_pkt: near
  305.     MakeExternal    drop_pkt: near
  306.     MakeExternal    get_address: near
  307.     MakeExternal    set_address: near
  308.     MakeExternal    terminate: near
  309.     MakeExternal    reset_interface: near
  310.     MakeExternal    xmit: near
  311.     MakeExternal    recv: near
  312.     MakeExternal    recv_exiting: near
  313.     MakeExternal    etopen: near
  314.  
  315.     MakeExternal    rcv_modes: word        ;count of modes followed by mode handles.
  316.  
  317.     MakeExternal    set_multicast_list: near
  318.  
  319. linc    macro    n            ; inc a 32 bit integer
  320.     local    a
  321.     inc    n            ;increment the low word
  322.     jne    a            ;go if not overflow
  323.     inc    n+2            ;increment the high word
  324. a:
  325.     endm
  326.  
  327. per_handle    struc
  328. in_use        db    0        ;non-zero if this handle is in use.
  329. packet_type    db    MAX_P_LEN dup(0);associated packet type.
  330. packet_type_len    dw    0        ;associated packet type length.
  331. receiver    dd    0        ;receiver handler.
  332. receiver_sig    db    8 dup(?)    ;signature at the receiver handler.
  333. class        db    ?        ;interface class
  334. per_handle    ends
  335.  
  336. handles        per_handle MAX_HANDLE dup(<>)
  337. end_handles    label    byte
  338.  
  339.     MakePublic    multicast_count, multicast_addrs, multicast_broad
  340. multicast_count    dw    0        ;count of stored multicast addresses.
  341. multicast_broad    db    0ffh,0ffh,0ffh,0ffh,0ffh,0ffh    ; entry for broadcast
  342. multicast_addrs    db    MAX_MULTICAST*EADDR_LEN dup(?)
  343.  
  344. have_my_address    db    0        ;nonzero if our address has been set.
  345. my_address    db    MAX_ADDR_LEN dup(?)
  346. my_address_len    dw    ?
  347.  
  348. rcv_mode_num    dw    3
  349.  
  350. free_handle    dw    0        ; temp, a handle not in use
  351. found_handle    dw    0        ; temp, handle for our packet
  352. receive_ptr    dd    0        ; the pkt receive service routine
  353.  
  354.     MakePublic    send_head, send_tail
  355. send_head    dd    0        ; head of transmit queue
  356. send_tail    dd    0        ; tail of transmit queue
  357.  
  358. statistics_list    label    dword
  359. packets_in    dw    ?,?
  360. packets_out    dw    ?,?
  361. bytes_in    dw    ?,?
  362. bytes_out    dw    ?,?
  363. errors_in    dw    ?,?
  364. errors_out    dw    ?,?
  365. packets_dropped    dw    ?,?        ;dropped due to no type handler.
  366.  
  367. savess        dw    ?        ;saved during the stack swap.
  368. savesp        dw    ?
  369.  
  370. regs    struc                ; stack offsets of incoming regs
  371. _ES    dw    ?
  372. _DS    dw    ?
  373. _BP    dw    ?
  374. _DI    dw    ?
  375. _SI    dw    ?
  376. _DX    dw    ?
  377. _CX    dw    ?
  378. _BX    dw    ?
  379. _AX    dw    ?
  380. _IP    dw    ?
  381. _CS    dw    ?
  382. _F    dw    ?            ; flags, Carry flag is bit 0
  383. regs    ends
  384.  
  385. CY    equ    0001h
  386. EI    equ    0200h
  387.  
  388.  
  389. bytes    struc                ; stack offsets of incoming regs
  390.     dw    ?            ; es, ds, bp, di, si are 16 bits
  391.     dw    ?
  392.     dw    ?
  393.     dw    ?
  394.     dw    ?
  395. _DL    db    ?
  396. _DH    db    ?
  397. _CL    db    ?
  398. _CH    db    ?
  399. _BL    db    ?
  400. _BH    db    ?
  401. _AL    db    ?
  402. _AH    db    ?
  403. bytes    ends
  404.  
  405.     MakePublic    our_isr, their_isr
  406.  
  407. their_isr    dd    0        ; original owner of pkt driver int
  408. our_isr:
  409.     jmp    our_isr_0        ;the required signature.
  410.     db    'PKT DRVR',0
  411. our_isr_0:
  412.     assume    ds:nothing
  413.     push    ax
  414.     push    bx
  415.     push    cx
  416.     push    dx
  417.     push    si
  418.     push    di
  419.     push    bp
  420.     push    ds
  421.     push    es
  422.     cld
  423.     mov    bx,cs            ;set up ds.
  424.     mov    ds,bx
  425.     assume    ds:code
  426.     mov    bp,sp            ;we use bp to access the original regs.
  427.     and    _F[bp],not CY        ;start by clearing the carry flag.
  428.  
  429.     mov    bl,ah            ;jump to the correct function.
  430.     mov    bh,0
  431.     cmp    bx,25            ;only twenty five functions right now.
  432.     mov    dh,BAD_COMMAND        ;in case we find a bad number.
  433.     ja    our_isr_error
  434.  
  435.     add    bx,bx            ;*2
  436.     call    functions[bx]
  437.     jnc    our_isr_return
  438.  
  439. our_isr_error:
  440.     mov    _DH[bp],dh
  441.     or    _F[bp],CY        ;return their carry flag.
  442.  
  443. our_isr_return:
  444.     pop    es
  445.     pop    ds
  446.     pop    bp
  447.     pop    di
  448.     pop    si
  449.     pop    dx
  450.     pop    cx
  451.     pop    bx
  452.     pop    ax
  453.     iret
  454.  
  455.     MakePublic    re_enable_interrupts
  456. re_enable_interrupts:
  457. ; Possibly re-enable interrupts.  We put this here so that other routines
  458. ; don't need to know how we put things on the stack.
  459.     test    _F[bp], EI        ; Were interrupts enabled on pkt driver entry?
  460.     je    re_enable_interrupts_1    ; No.
  461.     sti                ; Yes, re-enable interrupts now.
  462. re_enable_interrupts_1:
  463.     ret
  464.  
  465.  
  466. f_not_implemented:
  467.     mov    dh,BAD_COMMAND
  468.     stc
  469.     ret
  470.  
  471.  
  472. f_driver_info:
  473. ;    As of 1.08, the handle is optional, so we no longer verify it.
  474. ;    call    verify_handle
  475.     cmp    _AL[bp],0ffh        ; correct calling convention?
  476.     jne    f_driver_info_1        ; ne = incorrect, fail
  477.  
  478.                     ;For enhanced PD, if they call
  479.     cmp    _BX[bp],offset handles    ;with a handle, give them the
  480.                     ;class they think it is
  481.     jb    default_handle
  482.     cmp    _BX[bp],offset end_handles ;otherwise default to first class
  483.     jae    default_handle
  484.     mov    bx, _BX[bp]
  485.     cmp    [bx].in_use,0        ;if it's not in use, it's bad.
  486.     je    default_handle
  487.     mov    al, [bx].class
  488.     mov    _CH[bp], al
  489.     jmp    short got_handle
  490.  
  491. default_handle:
  492.     mov    al,driver_class
  493.     mov    _CH[bp],al
  494. got_handle:
  495.  
  496.     mov    _BX[bp],majver        ;version
  497.     mov    al,driver_type
  498.     cbw
  499.     mov    _DX[bp],ax
  500.     mov    _CL[bp],0        ;number zero.
  501.     mov    _DS[bp],ds        ; point to our name in their ds:si
  502.     mov    _SI[bp],offset driver_name
  503.     mov    al,driver_function
  504.     mov    _AL[bp],al
  505.     clc
  506.     ret
  507. f_driver_info_1:
  508.     stc
  509.     ret
  510.  
  511.  
  512. f_set_rcv_mode:
  513.     call    verify_handle
  514.  
  515.     cmp    cx,rcv_mode_num        ;are we already using that mode?
  516.     je    f_set_rcv_mode_4    ;yes, no need to check anything.
  517.  
  518.     mov    dx,bx            ;remember our handle.
  519.     mov    bx,offset handles    ; check that all handles are free
  520. f_set_rcv_mode_2:
  521.     cmp    bx,dx            ; is this our handle?
  522.     je    f_set_rcv_mode_3    ; yes, of course it's not free.
  523.     cmp    [bx].in_use,0        ; is this handle free?
  524.     jne    f_set_rcv_mode_1    ; ne = no, can't change
  525. f_set_rcv_mode_3:
  526.     add    bx,(size per_handle)    ; next handle
  527.     cmp    bx,offset end_handles    ; examined all handles?
  528.     jb    f_set_rcv_mode_2    ; b = no, continue examination
  529.  
  530.     mov    cx,_CX[bp]        ;get the desired receive mode.
  531.     cmp    cx,rcv_modes        ;do they have this many modes?
  532.     jae    f_set_rcv_mode_1    ;no - must be a bad mode for us.
  533.     mov    bx,cx
  534.     add    bx,bx            ;we're accessing words, not bytes.
  535.     mov    ax,rcv_modes[bx]+2    ;get the handler for this mode.
  536.     or    ax,ax            ;do they have one?
  537.     je    f_set_rcv_mode_1    ;no - must be a bad mode for us.
  538.     mov    rcv_mode_num,cx        ;yes - remember the number and
  539.     call    ax            ;  call it.
  540. f_set_rcv_mode_4:
  541.     clc
  542.     ret
  543. f_set_rcv_mode_1:
  544.     mov    dh,BAD_MODE
  545.     stc
  546.     ret
  547.  
  548.  
  549. f_get_rcv_mode:
  550.     call    verify_handle
  551.     mov    ax,rcv_mode_num        ;return the current receive mode.
  552.     mov    _AX[bp],ax
  553.     clc
  554.     ret
  555.  
  556.  
  557. f_set_multicast_list:
  558.     mov    cx,_CX[bp]        ;Tell them how much room they have.
  559.  
  560. ;verify that they supplied an even number of EADDR's.
  561.     mov    ax,cx
  562.     xor    dx,dx
  563.     mov    bx,EADDR_LEN
  564.     div    bx
  565.     or    dx,dx            ;zero remainder?
  566.     jne    f_set_multicast_list_2    ;no, we don't have an even number of
  567.                     ;  addresses.
  568.  
  569.     cmp    ax,MAX_MULTICAST    ;is this too many?
  570.     ja    f_set_multicast_list_3    ;yes - return NO_SPACE
  571. f_set_multicast_list_1:
  572.     mov    multicast_count,ax    ;remember the number of addresses.
  573.     push    cs
  574.     pop    es
  575.     mov    di,offset multicast_addrs
  576.     push    ds
  577.     mov    ds,_ES[bp]        ; get ds:si -> new list.
  578.     mov    si,_DI[bp]
  579.     push    cx
  580.     rep    movsb
  581.     pop    cx
  582.     pop    ds
  583.  
  584.     mov    si,offset multicast_addrs
  585.     call    set_multicast_list
  586.     ret
  587. f_set_multicast_list_2:
  588.     mov    dh,BAD_ADDRESS
  589.     stc
  590.     ret
  591. f_set_multicast_list_3:
  592.     mov    dh,NO_SPACE
  593.     stc
  594.     ret
  595.  
  596.  
  597. f_get_multicast_list:
  598.     mov    _ES[bp],ds        ;return what we have remembered.
  599.     mov    _DI[bp],offset multicast_addrs
  600.     mov    ax,EADDR_LEN        ;multiply the count by the length.
  601.     mul    multicast_count
  602.     mov    _CX[bp],ax        ;because they want total bytes.
  603.     clc
  604.     ret
  605.  
  606.  
  607. f_get_statistics:
  608.     call    verify_handle        ;just in case.
  609.     mov    _DS[bp],ds
  610.     mov    _SI[bp],offset statistics_list
  611.     clc
  612.     ret
  613.  
  614.  
  615. access_type_class:
  616.     mov    dh,NO_CLASS
  617.     stc
  618.     ret
  619.  
  620. access_type_type:
  621.     mov    dh,NO_TYPE
  622.     stc
  623.     ret
  624.  
  625. access_type_number:
  626.     mov    dh,NO_NUMBER
  627.     stc
  628.     ret
  629.  
  630. access_type_bad:
  631.     mov    dh,BAD_TYPE
  632.     stc
  633.     ret
  634.  
  635. ;register caller of pkt TYPE
  636. f_access_type:
  637.     mov    bx, offset driver_class
  638. access_type_9:
  639.     mov    al, [bx]        ;get the next class.
  640.     inc    bx
  641.     or    al,al            ;end of the list?
  642.     je    access_type_class    ;class failed (story of my life)
  643.     cmp    _AL[bp],al        ;our class?
  644.     jne    access_type_9        ;no, try again
  645. access_type_1:
  646.     cmp    _BX[bp],-1        ;generic type?
  647.     je    access_type_2        ;yes.
  648.     mov    al,driver_type
  649.     cbw
  650.     cmp    _BX[bp],ax        ;our type?
  651.     jne    access_type_type    ;no.
  652. access_type_2:
  653.     cmp    _DL[bp],0        ;generic number?
  654.     je    access_type_3
  655.     cmp    _DL[bp],1        ;our number?
  656.     jne    access_type_number
  657. access_type_3:
  658.     cmp    _CX[bp],MAX_P_LEN    ;is the type length too long?
  659.     ja    access_type_bad        ;yes - can't be ours.
  660.  
  661. ; now we do two things--look for an open handle, and check the existing
  662. ; handles to see if they're replicating a packet type.
  663.  
  664.     mov    free_handle,0        ;remember no free handle yet.
  665.     mov    bx,offset handles
  666. access_type_4:
  667.     cmp    [bx].in_use,0        ;is this handle in use?
  668.     je    access_type_5        ;no - don't check the type.
  669.     mov    al, _AL[bp]        ;is this handle the same class as
  670.     cmp    al, [bx].class        ;  they're want?
  671.     jne    short access_type_6
  672.     mov    es,_DS[bp]        ;get a pointer to their type
  673.     mov    di,_SI[bp]        ;  from their ds:si to our es:di
  674.     mov    cx,_CX[bp]        ;get the minimum of their length
  675.                     ;  and our length.  As currently
  676.                     ;  implemented, only one receiver
  677.                     ;  gets the packets, so we have to
  678.                     ;  ensure that the shortest prefix
  679.                     ;  is unique.
  680.     cmp    cx,[bx].packet_type_len    ;Are we less specific than they are?
  681.     jb    access_type_8        ;no.
  682.     mov    cx,[bx].packet_type_len    ;yes - use their count.
  683. access_type_8:
  684.     lea    si,[bx].packet_type
  685.     or    cx,cx            ; pass-all TYPE? (zero TYPE length)
  686.     jne    access_type_7        ; ne = no
  687.     mov    bx,offset handles+(MAX_HANDLE-1)*(size per_handle)
  688.     jmp    short access_type_5    ; put pass-all last
  689. access_type_7:
  690.     repe    cmpsb
  691.     jne    short access_type_6    ;go look at the next one.
  692. access_type_inuse:
  693.     mov    dh,TYPE_INUSE        ;a handle has been assigned for TYPE
  694.     stc                ;and we can't assign another
  695.     ret
  696. access_type_5:                ;handle is not in use
  697.     cmp    free_handle,0        ;found a free handle yet?
  698.     jne    access_type_6        ;yes.
  699.     mov    free_handle,bx        ;remember a free handle
  700. access_type_6:
  701.     add    bx,(size per_handle)    ;go to the next handle.
  702.     cmp    bx,offset end_handles    ;examined all handles?
  703.     jb    access_type_4        ;no, continue.
  704.  
  705.     mov    bx,free_handle        ;did we find a free handle?
  706.     or    bx,bx
  707.     je    access_type_space    ;no - return error.
  708.  
  709.     mov    [bx].in_use,1        ;remember that we're using it.
  710.  
  711.     mov    ax,_DI[bp]        ;remember the receiver type.
  712.     mov    [bx].receiver.offs,ax
  713.     mov    ax,_ES[bp]
  714.     mov    [bx].receiver.segm,ax
  715.  
  716.     push    ds
  717.     mov    ax,ds
  718.     mov    es,ax
  719.     mov    ds,_DS[bp]        ;remember their type.
  720.     mov    si,_SI[bp]
  721.     mov    cx,_CX[bp]
  722.     mov    es:[bx].packet_type_len,cx    ; remember the TYPE length
  723.     lea    di,[bx].packet_type
  724.     rep    movsb
  725.  
  726.     lds    si,es:[bx].receiver    ;copy the first 8 bytes
  727.     lea    di,[bx].receiver_sig    ; to the receiver signature.
  728.     mov    cx,8/2
  729.     rep    movsw
  730.  
  731.     pop    ds
  732.  
  733.     mov    al, _AL[bp]
  734.     mov    [bx].class, al
  735.  
  736.     mov    _AX[bp],bx        ;return the handle to them.
  737.  
  738.     clc
  739.     ret
  740.  
  741.  
  742. access_type_space:
  743.     mov    dh,NO_SPACE
  744.     stc
  745.     ret
  746.  
  747. f_release_type:
  748.     call    verify_handle        ;mark this handle as being unused.
  749.     mov    [bx].in_use,0
  750.     clc
  751.     ret
  752.  
  753.  
  754. f_send_pkt:
  755. ;ds:si -> buffer, cx = length
  756. ; XXX Should re-enable interrupts here, but some drivers are broken.
  757. ; Possibly re-enable interrupts.
  758. ;    test _F[bp], EI        ; Were interrupts enabled on pkt driver entry?
  759. ;    je    f_send_pkt_1    ; No.
  760. ;    sti            ; Yes, re-enable interrupts now.
  761. ;f_send_pkt_1:
  762.  
  763. ;following two instructions not needed because si and cx haven't been changed.
  764. ;    mov    si,_SI[bp]
  765. ;    mov    cx,_CX[bp]    ; count of bytes in the packet.
  766.     linc    packets_out
  767.     add    bytes_out.offs,cx    ;add up the received bytes.
  768.     adc    bytes_out.segm,0
  769.  
  770.     push    ds        ; set up proper ds for the buffer
  771.     mov    ds,_DS[bp]    ; address of buffer from caller's ds.
  772.     assume    ds:nothing, es:nothing
  773.  
  774. ; If -n option take Ethernet encapsulated Novell IPX packets (from BYU's 
  775. ; PDSHELL) and change them to be IEEE 802.3 encapsulated.
  776. EPROT_OFF    equ    EADDR_LEN*2
  777.     test    cs:flagbyte,N_OPTION
  778.     jz    f_send_pkt_2
  779.     cmp    ds:[si].EPROT_OFF,3781h ; if not Novell (prot 8137)
  780.     jne    f_send_pkt_2        ;  don't tread on it
  781.     push    ax            ; get scratch reg
  782.     mov    ax,[si].EPROT_OFF+4    ; get len
  783.     xchg    ah,al
  784.     inc    ax            ; make even (rounding up)
  785.     and    al,0feh
  786.     xchg    ah,al
  787.     mov    ds:[si].EPROT_OFF,ax    ; save in prot field
  788.     pop    ax            ; restore old contents
  789. f_send_pkt_2:
  790.     call    send_pkt
  791.     pop    ds
  792.     assume    ds:code
  793.     ret
  794.  
  795.  
  796. f_as_send_pkt:
  797. ;es:di -> iocb.
  798.     test    driver_function,4    ; is this a high-performance driver?
  799.     je    f_as_send_pkt_2        ; no.
  800. ; Possibly re-enable interrupts.
  801.     test _F[bp], EI            ; Were interrupts enabled on pkt driver entry?
  802.     je    f_as_send_pkt_1        ; No.
  803.     sti                ; Yes, re-enable interrupts now.
  804. f_as_send_pkt_1:
  805.     push    ds            ; set up proper ds for the buffer
  806.     lds    si,es:[di].buffer    ; ds:si -> buffer
  807.     assume    ds:nothing
  808.     mov    cx,es:[di].len        ; cx = length
  809.     linc    packets_out
  810.     add    bytes_out.offs,cx    ; add up the received bytes.
  811.     adc    bytes_out.segm,0
  812.  
  813. ;ds:si -> buffer, cx = length, es:di -> iocb.
  814.     call    as_send_pkt
  815.     pop    ds
  816.     assume    ds:code
  817.     ret
  818. f_as_send_pkt_2:
  819.     mov dh,    BAD_COMMAND        ; return an error.
  820.     stc
  821.     ret
  822.  
  823.  
  824. f_drop_pkt:
  825. ; es:di -> iocb.
  826.     test    driver_function,4    ; is this a high-performance driver?
  827.     je    f_as_send_pkt_1        ; no.
  828.     push    ds            ; Preserve ds
  829.     mov    si,offset send_head    ; Get head offset
  830. dp_loop:
  831.     mov    ax,ds:[si]        ; Get offset
  832.     mov    dx,ds:[si+2]        ; Get segment
  833.     mov    bx,ax
  834.     or    bx,dx            ; End of list?
  835.     je    dp_endlist        ; Yes
  836.     cmp    ax,di            ; Offsets equal?
  837.     jne    dp_getnext        ; No
  838.     mov    bx,es
  839.     cmp    dx,bx            ; Segments equal?
  840.     jne    dp_getnext        ; No
  841.     call    drop_pkt        ; Pass to driver
  842.     les    di,es:[di].next        ; Get next segment:offset
  843.     mov    ds:[si],di        ; Set next offset
  844.     mov    ds:[si+2],es        ; Set next segment
  845.     pop    ds            ; Restore ds
  846.     clc
  847.     ret
  848. dp_getnext:
  849.     mov    ds,dx            ; Get next segment
  850.     mov    si,ax            ; Get next iocb offset
  851.     lea    si,ds:[si].next        ; Get next iocb next ptr offset
  852.     jmp    dp_loop            ; Try again
  853. dp_endlist:
  854.     pop    ds            ; Restore ds
  855.     mov    dh,BAD_IOCB        ; Return error
  856.     stc                ; Set carry
  857.     ret
  858.  
  859.         MakeExternal    ser_funcs:near
  860. f_ser_func:                   ; direct serial functions
  861.     call    ser_funcs
  862.     clc
  863.     ret
  864.  
  865. f_terminate:
  866.     call    verify_handle        ; must have a handle
  867.  
  868. f_terminate_1:
  869.     mov    [bx].in_use,0        ; mark handle as free
  870.     mov    bx,offset handles    ; check that all handles are free
  871. f_terminate_2:
  872.     cmp    [bx].in_use,0        ; is this handle free?
  873.     jne    f_terminate_4        ; ne = no, so can't exit completely
  874.     add    bx,(size per_handle)    ; next handle
  875.     cmp    bx,offset end_handles    ; examined all handles?
  876.     jb    f_terminate_2        ; b = no, continue examination
  877.  
  878. ;
  879. ; Now disable interrupts
  880. ;
  881.     call    int_dis
  882.     call    terminate        ;terminate the hardware.
  883.  
  884.     mov    al,packet_int_no    ;release our_isr.
  885.     mov    ah,25h
  886.     push    ds
  887.     lds    dx,their_isr
  888.     int    21h
  889.     pop    ds
  890.  
  891. ;
  892. ; Now free our memory
  893. ;
  894.     push    cs
  895.     pop    es
  896.     mov    ah,49h
  897.     int    21h
  898.     clc
  899.     ret
  900. f_terminate_4:
  901.     mov    dh, CANT_TERMINATE
  902.     stc
  903.     ret
  904.  
  905.  
  906.     MakePublic    int_dis
  907. int_dis:
  908.     mov    al,int_no
  909.     or    al,al            ;are they using a hardware interrupt?
  910.     je    f_term_no_irq        ;no.
  911.  
  912.     call    maskint
  913.  
  914. ;
  915. ; Now return the interrupt to their handler.
  916. ;
  917.     mov    ah,25h            ;get the old interrupt into es:bx
  918.     mov    al,int_no
  919.     add    al,8
  920.     cmp    al,8+8            ;is it a slave 8259 interrupt?
  921.     jb    f_term_3        ;no.
  922.     add    al,70h - (8+8)        ;map it to the real interrupt.
  923. f_term_3:
  924.     push    ds
  925.     lds    dx,their_recv_isr
  926.     int    21h
  927.     pop    ds
  928.  
  929. f_term_no_irq:
  930.     ret
  931.  
  932.  
  933.  
  934.  
  935. f_get_address:
  936. ;    call    verify_handle
  937. ;    mov    es,_ES[bp]        ; get new one
  938. ;    mov    di,_DI[bp]        ; get pointer, es:di is ready
  939.     mov    cx,_CX[bp]        ;Tell them how much room they have.
  940.     cmp    have_my_address,0    ;has our address been set?
  941.     jne    get_address_set        ;yes - go report it.
  942.     call    get_address        ;no, can we get the address?
  943.     jc    get_address_space    ;no - we must not have enough space.
  944.     mov    _CX[bp],cx        ;Tell them how long our address is.
  945.     clc
  946.     ret
  947. get_address_set:
  948.     cmp    cx,my_address_len    ;is there enough room?
  949.     jb    get_address_space    ;no.
  950.     mov    cx,my_address_len    ;yes - get our address length.
  951.     mov    _CX[bp],cx        ;Tell them how long our address is.
  952.     mov    si,offset my_address    ;copy it into their area.
  953.     rep    movsb
  954.     clc
  955.     ret
  956.  
  957. get_address_space:
  958.     mov    dh,NO_SPACE
  959.     stc
  960.     ret
  961.  
  962.  
  963. f_set_address:
  964.     mov    bx,offset handles
  965.     mov    cl,0            ;number of handles in use.
  966. f_set_address_1:
  967.     add    cl,[bx].in_use        ;is this handle in use?
  968.     add    bx,(size per_handle)    ;go to the next handle.
  969.     cmp    bx,offset end_handles
  970.     jb    f_set_address_1
  971.  
  972.     cmp    cl,1            ;more than one handle in use?
  973.     ja    f_set_address_inuse    ;yes - we can't set the address
  974.  
  975.     mov    ds,_ES[bp]        ; set new one
  976.     assume    ds:nothing
  977.     mov    si,_DI[bp]        ; set pointer, ds:si is ready
  978.     mov    cx,_CX[bp]        ;Tell them how much address is being set.
  979.     call    set_address
  980. ;set_address restores ds.
  981.     jc    f_set_address_exit    ;Did it work?
  982.     mov    _CX[bp],cx        ;yes - return our address length.
  983.  
  984.     cmp    cx,MAX_ADDR_LEN        ;is it too long for us to remember?
  985.     ja    f_set_address_too_long    ;yes, return a too-long error.
  986.  
  987.     mov    ds,_ES[bp]        ; set new one
  988.     mov    si,_DI[bp]        ; set pointer, ds:si is ready
  989.     mov    ax,cs
  990.     mov    es,ax
  991.     mov    my_address_len,cx    ;remember how long our address is.
  992.     mov    di,offset my_address
  993.     rep    movsb
  994.     mov    have_my_address,1
  995.     mov    ds,ax            ;restoer ds.
  996.     assume    ds:code
  997.     clc
  998.     ret
  999. f_set_address_inuse:
  1000.     mov    dh,CANT_SET
  1001.     stc
  1002.     ret
  1003. f_set_address_too_long:
  1004.     mov    dh,NO_SPACE
  1005.     stc
  1006. f_set_address_exit:
  1007.     ret
  1008.  
  1009.  
  1010. f_reset_interface:
  1011.     call    verify_handle
  1012.     call    reset_interface
  1013.     clc
  1014.     ret
  1015.  
  1016.  
  1017. ; Stop the packet driver doing upcalls. Also a following terminate will
  1018. ; always succed (no in use handles any longer).
  1019. f_stop:
  1020.     mov    bx,offset handles
  1021. f_stop_2:
  1022.     mov    [bx].in_use,0
  1023.     add    bx,(size per_handle)    ; next handle
  1024.     cmp    bx,offset end_handles
  1025.     jb    f_stop_2
  1026.     clc
  1027.     ret
  1028.  
  1029.  
  1030. f_get_parameters:
  1031. ;strictly speaking, this function only works for high-performance drivers.
  1032.     test    driver_function,4    ;is this a high-performance driver?
  1033.     jne    f_get_parameters_1    ;yes.
  1034.     mov    dh,BAD_COMMAND        ;no - return an error.
  1035.     stc
  1036.     ret
  1037. f_get_parameters_1:
  1038.     mov    _ES[bp],cs
  1039.     mov    _DI[bp],offset parameter_list
  1040.     clc
  1041.     ret
  1042.  
  1043.  
  1044. verify_handle:
  1045. ;Ensure that their handle is real.  If it isn't, we pop off our return
  1046. ;address, and return to *their* return address with cy set.
  1047.     mov    bx,_BX[bp]        ;get the handle they gave us
  1048.     cmp    bx,offset handles
  1049.     jb    verify_handle_bad    ;no - must be bad.
  1050.     cmp    bx,offset end_handles
  1051.     jae    verify_handle_bad    ;no - must be bad.
  1052.     cmp    [bx].in_use,0        ;if it's not in use, it's bad.
  1053.     je    verify_handle_bad
  1054.     ret
  1055. verify_handle_bad:
  1056.     mov    dh,BAD_HANDLE
  1057.     add    sp,2            ;pop off our return address.
  1058.     stc
  1059.     ret
  1060.  
  1061.  
  1062.     MakePublic    set_recv_isr
  1063. set_recv_isr:
  1064.     mov    ah,35h            ;get the old interrupt into es:bx
  1065.     mov    al,int_no        ;board's interrupt vector
  1066.     or    al,al
  1067.     je    set_isr_no_irq
  1068.  
  1069.     add    al,8
  1070.     cmp    al,8+8            ;is it a slave 8259 interrupt?
  1071.     jb    set_recv_isr_1        ;no.
  1072.  
  1073.     add    al,70h - 8 - 8        ;map it to the real interrupt.
  1074.  
  1075. set_recv_isr_1:
  1076.     int    21h
  1077.     mov    their_recv_isr.offs,bx    ;remember the old seg:off.
  1078.     mov    their_recv_isr.segm,es
  1079.  
  1080.     mov    ah,25h            ;now set our recv interrupt.
  1081.     mov    dx,offset recv_isr
  1082.     int    21h
  1083.  
  1084.     mov    al,int_no        ; Now enable interrupts
  1085.     call    unmaskint
  1086.  
  1087. set_isr_no_irq:
  1088.     ret
  1089.  
  1090.  
  1091.  
  1092.     MakePublic    count_in_err
  1093. count_in_err:
  1094.     assume    ds:nothing
  1095.     linc    errors_in
  1096.     ret
  1097.  
  1098.     MakePublic    count_out_err
  1099. count_out_err:
  1100.     assume    ds:nothing
  1101.     linc    errors_out
  1102.     ret
  1103.  
  1104.      MakePublic    DelaySub
  1105.  
  1106. DelaySub:
  1107.          push   cx
  1108.          pop    cx
  1109.          ret
  1110.  
  1111. their_recv_isr    dd    0        ; original owner of board int
  1112.  
  1113. ;
  1114. ; I have had a problem with some hardware which under extreme LAN loading
  1115. ; conditions will re-enter the recv_isr. Since the 8259 interrupts for
  1116. ; the card are masked off, and the card's interrupt mask register is 
  1117. ; cleared (in 8390.asm at least) disabling the card from interrupting, this
  1118. ; is clearly a hardware problem. Due to the low frequencey of occurance, and
  1119. ; extreme conditions under which this happens, it is not lilely to be fixed
  1120. ; in hardware any time soon, plus retrofitting of hardware in the field will
  1121. ; not happen. To protect the driver from the adverse effects of this I am
  1122. ; adding a simple re-entrancy trap here.  - gft - 910617
  1123. ;
  1124.  
  1125. in_recv_isr    db     0    ; flag to trap re-entrancy
  1126.  
  1127. recv_isr:
  1128.     cmp    in_recv_isr, 0
  1129.     je    no_re_enter
  1130.     iret
  1131.  
  1132. no_re_enter:
  1133.     mov    in_recv_isr, 1
  1134.  
  1135. ; I realize this re-entrancy trap is not perfect, you could be re-entered
  1136. ; anytime before the above instruction. However since the stacks have not
  1137. ; been swapped re-entrancy here will only appear to be a spurious interrupt.
  1138. ; - gft - 910617
  1139.  
  1140. ; In order to achieve back-to-back packet transmissions, we handle the
  1141. ; latency-critical portion of transmit interrupts first.  The xmit
  1142. ; interrupt routine should only start the next transmission, but do
  1143. ; no other work.  It may only touch ax and dx (the only register necessary
  1144. ; for doing "out" instructions) unless it first pushes any other registers
  1145. ; itself.
  1146.     push    ax
  1147.     push    dx
  1148.     call    xmit
  1149.  
  1150. ; Now switch stacks, push remaining registers, and do remaining interrupt work.
  1151.     push    ds
  1152.     mov    ax,cs            ;ds = cs.
  1153.     mov    ds,ax
  1154.     assume    ds:code
  1155.  
  1156.     mov    savesp,sp
  1157.     mov    savess,ss
  1158.  
  1159.     mov    ss,ax
  1160.     mov    sp,offset our_stack
  1161.     cld
  1162.  
  1163.     push    bx
  1164.     push    cx
  1165.     push    si
  1166.     push    di
  1167.     push    bp
  1168.     push    es
  1169.  
  1170. ; The following comment is wrong in that we now do a specific EOI command,
  1171. ; and because we don't enable interrupts (even though we should).
  1172.  
  1173. ; Chips & Technologies 8259 clone chip seems to be very broken.  If you
  1174. ; send it a Non Specific EOI command, it clears all In Service Register
  1175. ; bits instead of just the one with the highest priority (as the Intel
  1176. ; chip does and clones should do).  This bug causes our interrupt
  1177. ; routine to be reentered if: 1. we reenable processor interrupts;
  1178. ; 2. we reenable device interrupts; 3. a timer or other higher priority
  1179. ; device interrupt now comes in; 4. the new interrupting device uses
  1180. ; a Non Specific EOI; 5. our device interrupts again.  Because of
  1181. ; this bug, we now completely mask our interrupts around the call
  1182. ; to "recv", the real device interrupt handler.  This allows us
  1183. ; to send an EOI instruction to the 8259 early, before we actually
  1184. ; reenable device interrupts.  Since the interrupt is masked, we
  1185. ; are still guaranteed not to get another interrupt from our device
  1186. ; until the interrupt handler returns.  This has another benefit:
  1187. ; we now no longer prevent other devices from interrupting while our
  1188. ; interrupt handler is running.  This is especially useful if we have
  1189. ; other (multiple) packet drivers trying to do low-latency transmits.
  1190.     mov    al,int_no    ; Disable further device interrupts
  1191.     call    maskint
  1192.  
  1193. ; The following is from Bill Rust, <wjr@ftp.com>
  1194. ; this code dismisses the interrupt at the 8259. if the interrupt number
  1195. ;  is > 8 then it requires fondling two PICs instead of just one.
  1196.     mov    al, int_no    ; get hardware int #
  1197.     cmp    al, 8        ; see if its on secondary PIC
  1198.     jg    recv_isr_4
  1199.     add    al, 60h        ; make specific EOI dismissal
  1200.     out    20h, al
  1201.     jmp    recv_isr_3    ; all done
  1202.  
  1203. recv_isr_4:
  1204.     add    al,60h - 8    ; make specific EOI (# between 9 & 15).
  1205.     out    0a0h,al        ; Secondary 8259 (PC/AT only)
  1206.     mov    al,62h        ; Acknowledge on primary 8259.
  1207.     out    20h,al
  1208. recv_isr_3:
  1209.  
  1210. ;    sti                ; Interrupts are now completely safe
  1211.     call    recv
  1212.  
  1213.     cli                ;interrupts *must* be off between
  1214.                     ;here and the stack restore, because
  1215.                     ;if we have one of our interrupts
  1216.                     ;pending, we would trash our stack.
  1217. ;
  1218. ; According to Novell IMSP Technical Memo #2, Lost Interrupts and NetWare,
  1219. ; some LAN controllers can glitch the interrupt line when the interrupt
  1220. ; mask register on the LAN controller is enabled to allow the LAN controller
  1221. ; to interrupt. This can cause spurious/lost interrupt problems, especially
  1222. ; on some 486 processors which latch the int line to the processor. To prevent
  1223. ; glitches from being propogated throug, move the call to recv_exiting (re-
  1224. ; enables interrupts on the LAN card) to before when the 8259 interrupts are
  1225. ; unmasked. - gft - 910617
  1226.  
  1227.     call    recv_exiting
  1228.  
  1229.     mov    al,int_no    ; Now reenable device interrupts
  1230.     call    unmaskint
  1231.  
  1232.     pop    es
  1233.     pop    bp
  1234.     pop    di
  1235.     pop    si
  1236.     pop    cx
  1237.     pop    bx
  1238.  
  1239.     mov    ss,savess
  1240.     mov    sp,savesp
  1241.  
  1242. ; move the next call up to above the call unmaskint - gft - 910617
  1243. ;    call    recv_exiting        ;this routine can enable interrupts.
  1244. ; DDP - This is a BIG mistake.  This routine SHOULD NOT enable interrupts.
  1245. ;    doing so can cause interrupt recursion and blow your stack.
  1246. ;    Processor interrupts SHOULD NOT be enabled after enabling device
  1247. ;    interrupts until after the "iret".  You will lose atleast 12 bytes
  1248. ;    on the stack for each recursion.
  1249.  
  1250.     pop    ds
  1251.     assume    ds:nothing
  1252.     pop    dx
  1253.     pop    ax
  1254.     mov    in_recv_isr, 0    ; clear the re-entrancy flag - gft - 901617
  1255.     iret
  1256.  
  1257.  
  1258.     MakePublic    maskint
  1259. maskint:
  1260.     or    al,al            ;are they using a hardware interrupt?
  1261.     je    maskint_1        ;no, don't mask off the timer!
  1262.  
  1263.     assume    ds:code
  1264.     mov    dx,21h            ;assume the master 8259.
  1265.     cmp    al,8            ;using the slave 8259 on an AT?
  1266.     jb    mask_not_irq2
  1267.     mov    dx,0a1h            ;go disable it on slave 8259
  1268.     sub    al,8
  1269. mask_not_irq2:
  1270.     mov    cl,al
  1271.  
  1272.     SlowIn                ;disable them on the correct 8259.
  1273.     mov    ah,1            ;set the bit.
  1274.     shl    ah,cl
  1275.     or    al,ah
  1276. ;
  1277. ; 500ns Stall required here, per INTEL documentation for eisa machines
  1278. ; - gft - 910617
  1279. ;
  1280.     Delay
  1281.     SlowOut
  1282.  
  1283. maskint_1:
  1284.     ret
  1285.  
  1286.  
  1287.     MakePublic    unmaskint
  1288. unmaskint:
  1289.     assume    ds:code
  1290.     mov    dx,21h            ;assume the master 8259.
  1291.     mov    cl,al
  1292.     cmp    cl,8            ;using the slave 8259 on an AT?
  1293.     jb    unmask_not_irq2        ;no
  1294.  
  1295.     SlowIn                ;get master mask
  1296.     and    al,not (1 shl 2)    ; and clear slave cascade bit in mask
  1297.     SlowOut                ;set new master mask (enable slave int)
  1298. ;
  1299. ; 500ns Stall required here, per INTEL documentation for eisa machines
  1300. ; - gft - 910617
  1301. ;
  1302.     mov    dx,0a1h            ;go enable int on slave 8259
  1303.     sub    cl,8
  1304.  
  1305. unmask_not_irq2:
  1306.  
  1307.     SlowIn                ;enable interrupts on the correct 8259.
  1308.     mov    ah,1            ;clear the bit.
  1309.     shl    ah,cl
  1310.     not    ah
  1311.     and    al,ah
  1312. ;
  1313. ; 500ns Stall required here, per INTEL documentation for eisa machines
  1314. ; - gft - 910617
  1315. ;
  1316.     SlowOut
  1317.     ret
  1318.  
  1319.  
  1320.     MakePublic    recv_find
  1321. recv_find:
  1322. ;called when we want to determine what to do with a received packet.
  1323. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  1324. ;exit with es:di = 0 if the packet is not desired, or es:di -> packet buffer
  1325. ;  to be filled by the driver.
  1326.     assume    ds:code, es:nothing
  1327.     push    cx
  1328.  
  1329. ; If -n option take IEEE 802.3 encapsulated packets that could be Novell IPX 
  1330. ; and make them Ethernet encapsulated Novell IPX packets (for PDSHELL).
  1331.     test    flagbyte,N_OPTION
  1332.     jz    not_n_op
  1333.  
  1334. ; Make IEEE 802.3-like packets that could be Novell IPX into BlueBook class
  1335. ; Novell type 8137 packets.
  1336.     cmp    dl,IEEE8023        ;Is this an IEEE 802.3 packet?
  1337.     jne    recv_not_802_3        ;no
  1338.     cmp    word ptr es:[di],0ffffh    ;if this word not ffff
  1339.     jne    recv_not_8137        ;  then not Novell
  1340.     sub    di,2            ; back it up to the 8137 word.
  1341.     mov    es:[di],3781h        ; fake as Novell protocol (8137)
  1342.     mov    dl,BLUEBOOK
  1343.     jmp    short recv_not_8137
  1344. recv_not_802_3:
  1345. ; Convert incoming Ethernet type 8137 IPX packets to type 8138, as with -n in 
  1346. ; effect we can't send type 8137, and it will only confuse Netware.
  1347.     cmp    dl,BLUEBOOK        ;Is this a BLUEBOOK packet?
  1348.     jne    recv_not_8137        ;no, don't change it.
  1349.     cmp    word ptr es:[di],3781h    ;Is it an 8137 packet?
  1350.     jne    recv_not_8137        ;no, don't change it.
  1351.     mov    es:[di],word ptr 3881h    ;yes, mung it slightly.
  1352. recv_not_8137:
  1353. not_n_op:
  1354.  
  1355.     mov    bx,offset handles
  1356. recv_find_1:
  1357.     cmp    [bx].in_use,0        ;is this handle in use?
  1358.     je    recv_find_2        ;no - don't check the type.
  1359.  
  1360.     mov    ax,[bx].receiver.offs    ;do they have a receiver?
  1361.     or    ax,[bx].receiver.segm
  1362.     je    recv_find_2        ;no - they're not serious about it.
  1363.  
  1364.     mov    cx,[bx].packet_type_len    ;compare the packets.
  1365.     lea    si,[bx].packet_type
  1366.     jcxz    recv_find_3        ;if cx is zero, they want them all.
  1367.  
  1368.     cmp    [bx].class, dl        ;is this the right class?
  1369.     jne    recv_find_2        ;no- don't bother
  1370.  
  1371.     push    di
  1372.     repe    cmpsb
  1373.     pop    di
  1374.     je    recv_find_3        ;we've got it!
  1375. recv_find_2:
  1376.     add    bx,(size per_handle)    ;go to the next handle.
  1377.     cmp    bx,offset end_handles
  1378.     jb    recv_find_1
  1379.  
  1380.     linc    packets_dropped
  1381.  
  1382.     pop    cx            ;we didn't find it -- discard it.
  1383. recv_find_5:
  1384.     xor    di,di            ;"return" a null pointer.
  1385.     mov    es,di
  1386.     ret
  1387. recv_find_3:
  1388.     pop    cx            ; the packet_length
  1389.  
  1390.     linc    packets_in
  1391.     add    bytes_in.offs,cx    ;add up the received bytes.
  1392.     adc    bytes_in.segm,0
  1393.  
  1394.     les    di,[bx].receiver    ;remember the receiver upcall.
  1395.     mov    receive_ptr.offs,di
  1396.     mov    receive_ptr.segm,es
  1397.  
  1398.     test    flagbyte,W_OPTION    ;did they select the Windows option?
  1399.     je    recv_find_6        ;no, don't check for the upcall.
  1400.  
  1401. ; does the receiver signature match whats currently in memory?  if not,
  1402. ; jump to fake return
  1403.     push    si
  1404.     push    cx
  1405.     lea    si,[bx].receiver_sig
  1406.     mov    cx,8/2
  1407.     repe    cmpsw
  1408.     pop    cx
  1409.     pop    si
  1410.     jne    recv_find_5
  1411. recv_find_6:
  1412.  
  1413.     mov    found_handle,bx        ;remember what our handle was.
  1414.     mov    ax,0            ;allocate request.
  1415.     stc                ;with stc, flags must be an odd number
  1416.     push    ax            ; save a number that cant be flags
  1417.     pushf                ;save flags in case iret used.
  1418.     call    receive_ptr        ;ask the client for a buffer.
  1419.     ; on return, flags should be at top of stack. if an IRET has been used,
  1420.     ; then 0 will be at the top of the stack
  1421.     pop    bx
  1422.     cmp    bx,0
  1423.     je    recv_find_4        ;0 is at top of stack
  1424.     add    sp,2
  1425. recv_find_4:
  1426.     ret
  1427.  
  1428.  
  1429.     MakePublic    recv_copy
  1430. recv_copy:
  1431. ;called after we have copied the packet into the buffer.
  1432. ;enter with ds:si ->the packet, cx = length of the packet.
  1433. ;preserve bx.
  1434.     assume    ds:nothing, es:nothing
  1435.  
  1436.     push    bx
  1437.     mov    bx,found_handle
  1438.     mov    ax,1            ;store request.
  1439.     clc                ;with clc, flags must be an even number
  1440.     push    ax            ; save a number that can't be flags
  1441.     pushf                ;save flags incase iret used.
  1442.     call    receive_ptr        ;ask the client for a buffer.
  1443.     pop    bx
  1444.     cmp    bx,1            ;if this is a 1, IRET was used.
  1445.     je    recv_copy_1
  1446.     pop    bx
  1447. recv_copy_1:
  1448.     pop    bx
  1449.     ret
  1450.  
  1451.     MakePublic    send_queue
  1452. send_queue:
  1453. ; Queue an iocb.
  1454. ; Enter with es:di -> iocb, interrupts disabled.
  1455. ; Destroys ds:si.
  1456.     assume    ds:nothing, es:nothing
  1457.     mov    es:[di].next.offs,0    ; Zero next offset
  1458.     mov    es:[di].next.segm,0    ; Zero next segment
  1459.     mov    si,send_head.offs    ; Queue empty?
  1460.     or    si,send_head.segm
  1461.     jnz    sq_notempty        ; No
  1462.     mov    send_head.offs,di    ; Set head offset
  1463.     mov    send_head.segm,es    ; Set head segment
  1464.     jmp    sq_settail
  1465. sq_notempty:                ; Queue is not empty
  1466.     lds    si,send_tail        ; Get tail segment:offset
  1467.     mov    ds:[si].next.offs,di    ; Set next offset
  1468.     mov    ds:[si].next.segm,es    ; Set next segment
  1469. sq_settail:
  1470.     mov    send_tail.offs,di    ; Set tail offset
  1471.     mov    send_tail.segm,es    ; Set tail segment
  1472.     ret
  1473.  
  1474.  
  1475.     MakePublic    send_dequeue
  1476. send_dequeue:
  1477. ; Dequeue an iocb and possibly call its upcall.
  1478. ; Enter with device or processor interrupts disabled, ah = return code.
  1479. ; Exits with es:di -> iocb; destroys ds:si, ax, bx, cx, dx, bp.
  1480.     assume    ds:nothing, es:nothing
  1481.     les    di,send_head        ; Get head segment:offset
  1482.     lds    si,es:[di].next        ; Get next segment:offset
  1483.     mov    send_head.offs, si    ; Set head offset
  1484.     mov    send_head.segm, ds    ; Set head segment
  1485.     or    es:flags[di], DONE    ; Mark done
  1486.     mov    es:ret_code[di], ah    ; Set retcode
  1487.     test    es:[di].flags,CALLME    ; Does he want an upcall?
  1488.     je    send_dequeue_1        ; No.
  1489.     push    es            ; Push iocb segment
  1490.     push    di            ;  and offset
  1491.     clc                ; Clear carry.
  1492.     mov    ax,1            ; Push a number that cant be flags.
  1493.     push    ax
  1494.     pushf                ; Save flags in case iret used.
  1495.     call    es:[di].upcall        ; Call the client.
  1496.     pop    ax            ; Pop first word.
  1497.     cmp    ax,1            ; If this is a 1, IRET was used.
  1498.     je    send_dequeue_2        ; Far return used.
  1499.     add    sp,2            ; Pop flags.
  1500. send_dequeue_2:
  1501.     pop    di            ; Pop iocb segment
  1502.     pop    es            ;  and offset
  1503. send_dequeue_1:
  1504.     ret
  1505.  
  1506.  
  1507. code    ends
  1508.  
  1509. ;;;grg    equ    99
  1510.  
  1511. base        =    50
  1512.  
  1513. Alloc   macro   var,len
  1514. &var    equ     base*2
  1515. base    =     base+1+0&len
  1516.         endm
  1517.  
  1518.                 Alloc   col_chout
  1519.                 Alloc   col_chin
  1520.                 Alloc   col_ovrr,2
  1521.                 Alloc   col_frame,2
  1522.                 Alloc   col_serfull,2
  1523.                 Alloc   col_TCPFull,2
  1524.                 Alloc   col_InIn
  1525.                 Alloc   col_InOut
  1526.                 Alloc   col_inmove
  1527.                 Alloc   col_paks
  1528.  
  1529. Show    macro    Col,Ch
  1530.   ifdef  grg
  1531.       push    es
  1532.     push    ax
  1533.         mov    ax,0B800h
  1534.         mov    es,ax
  1535.         mov    byte ptr es:[&col],&Ch        ; twiddle screen if buf full
  1536.     pop    ax
  1537.     pop    es
  1538.   endif
  1539.       endm
  1540.  
  1541.  
  1542. ShowInc    macro    Col,Ch
  1543.   ifdef  grg
  1544.       push    es
  1545.     push    ax
  1546.         mov    ax,0B800h
  1547.         mov    es,ax
  1548.         mov    byte ptr es:[&col],&Ch
  1549.         inc    byte ptr es:[&col+2]
  1550.     pop    ax
  1551.     pop    es
  1552.   endif
  1553.       endm
  1554.  
  1555.  
  1556. TheVersion    equ    1
  1557. majver        equ    1        ;version number of the infrastructure.
  1558.  
  1559. MAX_ADDR_LEN    equ    16        ;maximum number of bytes in our address.
  1560.  
  1561. MAX_HANDLE    equ    10        ;maximum number of handles.
  1562.  
  1563. MAX_P_LEN    equ    8        ;maximum type length
  1564.  
  1565. MAX_MULTICAST    equ    8        ;maximum number of multicast addresses.
  1566.  
  1567. ;  Copyright, 1988-1992, Russell Nelson, Crynwr Software
  1568.  
  1569. ;   This program is free software; you can redistribute it and/or modify
  1570. ;   it under the terms of the GNU General MakePublic License as published by
  1571. ;   the Free Software Foundation, version 1.
  1572. ;
  1573. ;   This program is distributed in the hope that it will be useful,
  1574. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  1575. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1576. ;   GNU General MakePublic License for more details.
  1577. ;
  1578. ;   You should have received a copy of the GNU General MakePublic License
  1579. ;   along with this program; if not, write to the Free Software
  1580. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1581.  
  1582. HT    equ    09h
  1583. CR    equ    0dh
  1584. LF    equ    0ah
  1585.  
  1586. ;
  1587. ;  Packet Driver Error numbers
  1588. NO_ERROR    equ    0        ;no error at all.
  1589. BAD_HANDLE    equ    1        ;invalid handle number
  1590. NO_CLASS    equ    2        ;no interfaces of specified class found
  1591. NO_TYPE        equ    3        ;no interfaces of specified type found
  1592. NO_NUMBER    equ    4        ;no interfaces of specified number found
  1593. BAD_TYPE    equ    5        ;bad packet type specified
  1594. NO_MULTICAST    equ    6        ;this interface does not support
  1595.                     ;multicast
  1596. CANT_TERMINATE    equ    7        ;this packet driver cannot terminate
  1597. BAD_MODE    equ    8        ;an invalid receiver mode was specified
  1598. NO_SPACE    equ    9        ;operation failed because of
  1599.                     ;insufficient space
  1600. TYPE_INUSE    equ    10        ;the type had previously been accessed,
  1601.                     ;and not released.
  1602. BAD_COMMAND    equ    11        ;the command was out of range, or not
  1603.                     ;implemented
  1604. CANT_SEND    equ    12        ;the packet couldn't be sent (usually
  1605.                     ;hardware error)
  1606. CANT_SET    equ    13        ;hardware address couldn't be changed
  1607.                     ;(more than 1 handle open)
  1608. BAD_ADDRESS    equ    14        ;hardware address has bad length or
  1609.                     ;format
  1610. CANT_RESET    equ    15        ;Couldn't reset interface (more than
  1611.                     ;1 handle open).
  1612. BAD_IOCB    equ    16        ;an invalid iocb was specified
  1613.  
  1614. ;a few useful Ethernet definitions.
  1615. RUNT        equ    60        ;smallest legal size packet, no fcs
  1616. GIANT        equ    1514        ;largest legal size packet, no fcs
  1617. EADDR_LEN    equ    6        ;Ethernet address length.
  1618. ARCADDR_LEN    equ    1
  1619.  
  1620. BLUEBOOK    equ    1
  1621. IEEE8023    equ    11
  1622.  
  1623. ;The following two macros are used to manipulate port addresses.
  1624. ;Use loadport to initialize dx.  Use setport to set a specific port on
  1625. ;the board.  setport remembers what the current port number is, but beware!
  1626. ;setport assumes that code is being executed in the same order as the
  1627. ;code is presented in the source file.  Whenever this assumption is violated,
  1628. ;you need to enter another loadport.  Some, but not all examples are:
  1629. ;in a loop with multiple setports, or a backward jump over a setport, or
  1630. ;a forward jump over a setport.  If you have any doubt, consult the
  1631. ;individual driver sources for examples of usage.  If you suspect that
  1632. ;you have too few loadports, define the symbol "no_confidence" to a
  1633. ;one.  This will force a loadport before every setport.  If you wish to turn
  1634. ;it off for some of your code, redefine it to a zero.
  1635.  
  1636. loadport    macro
  1637.     mov    dx,io_addr
  1638. port_no    =    0
  1639.     endm
  1640.  
  1641. ;change the port number from the current value to the new value.
  1642. setport    macro    new_port_no
  1643.     ifdef    no_confidence        ;define if you suspect that you don't
  1644.       if    no_confidence
  1645.         loadport        ;  have enough loadports, i.e. dx is
  1646.       endif
  1647.     endif                ;  set to the wrong port.
  1648.     if    new_port_no - port_no EQ 1
  1649.         inc    dx
  1650.     else
  1651.         if    new_port_no - port_no EQ -1
  1652.             dec    dx
  1653.         else
  1654.             if    new_port_no - port_no NE 0
  1655.                 add    dx,new_port_no - port_no
  1656.             endif
  1657.         endif
  1658.     endif
  1659. port_no    =    new_port_no
  1660.     endm
  1661.  
  1662. Print    macro
  1663.     call    DosPrint
  1664.         endm
  1665.  
  1666. Delay           Macro
  1667.                 call  DelaySub
  1668.                 endm
  1669.  
  1670.  
  1671.  
  1672. SlowIn    macro
  1673.     Delay
  1674.         in    al,dx
  1675.         endm
  1676.  
  1677.  
  1678. SlowOut    macro
  1679.     Delay
  1680.         out    dx,al
  1681.         endm
  1682.  
  1683.  
  1684. segmoffs    struc            ; defines offs as 0, segm as 2
  1685. offs        dw    ?
  1686. segm        dw    ?
  1687. segmoffs    ends
  1688.  
  1689. CY    equ    0001h
  1690. EI    equ    0200h
  1691.  
  1692. iocb        struc            ; as_send_pkt structure
  1693. buffer        dd    ?        ; Pointer to the buffer
  1694. len        dw    ?        ; Its length
  1695. flags        db    ?        ; Some flags
  1696. ret_code    db    ?        ; Completion code
  1697. upcall        dd    ?        ; I/O completion upcall
  1698. next        dd    ?        ; Private next pointer (queue)
  1699. resv        db    4 dup (?)    ; Unused private data
  1700. iocb        ends
  1701.  
  1702. DONE    equ    1        ; I/O complete flag
  1703. CALLME    equ    2        ; Please upcall me flag
  1704.  
  1705.  
  1706. send_queueempty    macro
  1707. ; Check if send queue is empty.
  1708. ; Enter with interrupts disabled.
  1709. ; Exit with zr (zero) if empty, nz (not zero) if not.
  1710. ; Destroys ax.
  1711.     mov ax,    word ptr send_head    ; Queue empty?
  1712.     or ax,    word ptr send_head+2
  1713.     endm
  1714.  
  1715. send_peekqueue    macro
  1716. ; Peek into the queue and get the next entry.
  1717. ; Enter with interrupts disabled.
  1718. ; Exit with es:di -> iocb.
  1719.     les di, send_head    ; Get head segment:offset
  1720.     endm
  1721.  
  1722. ; Bits in sys_features
  1723. MICROCHANNEL    equ    02        ; a micro channel computer
  1724. TWO_8259    equ    40h        ; 2nd 8259 exists
  1725.  
  1726. ; Bits in flagbyte
  1727. CALLED_ETOPEN    equ    1        ; have called etopen
  1728. D_OPTION    equ    2        ; delayed initialization
  1729. N_OPTION    equ    4        ; Novell protocol conversion
  1730. W_OPTION    equ    8        ; Windows upcall checking.
  1731.  
  1732. ;Ported from Phil Karn's asy.c and slip.c, a C-language driver for the IBM-PC
  1733. ;8250 by Russell Nelson.  Any bugs are due to Russell Nelson.
  1734. ;16550 support ruthlessly stolen from Phil Karn's 8250.c. 
  1735. ;  Bugs by Denis DeLaRoca
  1736. ; Stopped failures from lost transmit interrupts (by eliminating the ints
  1737. ; altogether). Remove unneeded transmitter buffer.
  1738. ; Version 6 by Joe Doupnik, jrd@cc.usu.edu, Utah State University, Dec 1991.
  1739.  
  1740. ;  Copyright, 1988, 1991, Russell Nelson
  1741.  
  1742. ;   This program is free software; you can redistribute it and/or modify
  1743. ;   it under the terms of the GNU General MakePublic License as published by
  1744. ;   the Free Software Foundation, version 1.
  1745. ;
  1746. ;   This program is distributed in the hope that it will be useful,
  1747. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  1748. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1749. ;   GNU General MakePublic License for more details.
  1750. ;
  1751. ;   You should have received a copy of the GNU General MakePublic License
  1752. ;   along with this program; if not, write to the Free Software
  1753. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1754.  
  1755. code    segment    word
  1756.     assume    cs:code, ds:code
  1757.  
  1758. ;8250 definitions
  1759. ;Control/status register offsets from base address
  1760. THR    equ    0        ;Transmitter holding register
  1761. RBR    equ    0        ;Receiver buffer register
  1762. DLL    equ    0        ;Divisor latch LSB
  1763. DLM    equ    1        ;Divisor latch MSB
  1764. IER    equ    1        ;Interrupt enable register
  1765. IIR    equ    2        ;Interrupt ident register
  1766. FCR    equ    2        ;16550 FIFO control register
  1767. LCR    equ    3        ;Line control register
  1768. MCR    equ    4        ;Modem control register
  1769. LSR    equ    5        ;Line status register
  1770. MSR    equ    6        ;Modem status register
  1771.  
  1772. ;8250 Line Control Register
  1773. LCR_5BITS    equ    0    ;5 bit words
  1774. LCR_6BITS    equ    1    ;6 bit words
  1775. LCR_7BITS    equ    2    ;7 bit words
  1776. LCR_8BITS    equ    3    ;8 bit words
  1777. LCR_NSB        equ    4    ;Number of stop bits
  1778. LCR_PEN        equ    8    ;Parity enable
  1779. LCR_EPS        equ    10h    ;Even parity select
  1780. LCR_SP        equ    20h    ;Stick parity
  1781. LCR_SB        equ    40h    ;Set break
  1782. LCR_DLAB    equ    80h    ;Divisor Latch Access Bit
  1783.  
  1784. ;16550 FIFO control register values
  1785. FIFO_ENABLE     equ     001h    ;Enable TX and RX fifo
  1786. FIFO_CLR_RX     equ     002h    ;Clear RX fifo
  1787. FIFO_CLR_TX     equ     004h    ;Clear TX fifo
  1788. FIFO_START_DMA  equ     008h    ;Enable TXRDY/RXRDY pin DMA handshake
  1789. FIFO_SIZE_1     equ     000h    ;RX fifo trigger levels
  1790. FIFO_SIZE_4     equ     040h
  1791. FIFO_SIZE_8     equ     080h
  1792. FIFO_SIZE_14    equ     0c0h
  1793. FIFO_SIZE_MASK  equ     0c0h
  1794.  
  1795. FIFO_TRIGGER_LEVEL equ FIFO_SIZE_4
  1796. FIFO_SETUP         equ FIFO_ENABLE+FIFO_CLR_RX+FIFO_CLR_TX+FIFO_TRIGGER_LEVEL
  1797. OUTPUT_FIFO_SIZE   equ 16
  1798.  
  1799. ;8250 Line Status Register
  1800. LSR_DR    equ    1    ;Data ready
  1801. LSR_OE    equ    2    ;Overrun error
  1802. LSR_PE    equ    4    ;Parity error
  1803. LSR_FE    equ    8    ;Framing error
  1804. LSR_BI    equ    10h    ;Break interrupt
  1805. LSR_THRE equ    20h    ;Transmitter line holding register empty
  1806. LSR_TSRE equ    40h    ;Transmitter shift register empty
  1807.  
  1808. ;8250 Interrupt Identification Register
  1809. IIR_IP        equ    1    ;0 if interrupt pending
  1810. IIR_ID        equ    6    ;Mask for interrupt ID
  1811. IIR_RLS        equ    6    ;Receiver Line Status interrupt
  1812. IIR_RDA        equ    4    ;Receiver data available interrupt
  1813. IIR_THRE    equ    2    ;Transmitter holding register empty int
  1814. IIR_MSTAT    equ    0    ;Modem status interrupt
  1815. IIR_FIFO_TIMEOUT  equ   008h    ;FIFO timeout interrupt pending - 16550 only
  1816. IIR_FIFO_ENABLED  equ   080h    ;FIFO enabled (FCR0 = 1) - 16550 only
  1817.  
  1818. ;8250 interrupt enable register bits
  1819. IER_DAV    equ    1    ;Data available interrupt
  1820. IER_TxE    equ    2    ;Tx buffer empty interrupt
  1821. IER_RLS    equ    4    ;Receive line status interrupt
  1822. IER_MS    equ    8    ;Modem status interrupt
  1823.  
  1824. ;8250 Modem control register
  1825. MCR_DTR    equ    1    ;Data Terminal Ready
  1826. MCR_RTS    equ    2    ;Request to Send
  1827. MCR_OUT1 equ    4    ;Out 1 (not used)
  1828. MCR_OUT2 equ    8    ;Master interrupt enable (actually OUT 2)
  1829. MCR_LOOP equ    10h    ;Loopback test mode
  1830.  
  1831. ;8250 Modem Status Register
  1832. MSR_DCTS equ    1    ;Delta Clear-to-Send
  1833. MSR_DDSR equ    2    ;Delta Data Set Ready
  1834. MSR_TERI equ    4    ;Trailing edge ring indicator
  1835. MSR_DRLSD equ    8    ;Delta Rx Line Signal Detect
  1836. MSR_CTS equ    10h    ;Clear to send
  1837. MSR_DSR equ    20h    ;Data set ready
  1838. MSR_RI    equ    40h    ;Ring indicator
  1839. MSR_RLSD equ    80h    ;Received line signal detect
  1840.  
  1841. pr_ch_al    macro        alvalue
  1842. ifdef TRACEON
  1843.     mov    al,alvalue
  1844.     call    pr_ch
  1845. endif
  1846.     endm
  1847.  
  1848. ;Slip Definitions
  1849. FR_END        equ    0c0h        ;Frame End
  1850. FR_ESC        equ    0dbh        ;Frame Escape
  1851. T_FR_END    equ    0dch        ;Transposed frame end
  1852. T_FR_ESC    equ    0ddh        ;Transposed frame escape
  1853.  
  1854. ser_buf_size    equ    3000        ; (grg)
  1855.  
  1856. BRC        equ    115200
  1857.  
  1858.     MakePublic    int_no
  1859. TheInfo:
  1860. int_no        db    4,0,0,0        ; interrupt number.
  1861. io_addr        dw    03f8h,0        ; I/O address for COM1
  1862. baud_rate    dw    1234,0        ; support baud higher than 65535
  1863. ser_misc        db      LCR_8BITS,0,0,0    ; misc control bits
  1864. hardware_switch    db    0,0,0,0        ; if zero, don't use hw handshaking
  1865. xmit_time    dw    0,0        ; loop timer for ari
  1866.  
  1867. baudclk        label    word
  1868.         dd    BRC        ; 1.8432 Mhz / 16
  1869.  
  1870. is_16550        db      0               ; 0=no, 1=yes (try using fifo)
  1871.  
  1872.     MakePublic    driver_class, driver_type, driver_name
  1873.     MakePublic    driver_function, parameter_list
  1874. driver_class    db    6,0,0,0        ;from the packet spec
  1875. driver_type    db    0,0,0,0        ;from the packet spec
  1876. driver_name    db    'UMSLIP  ',0    ;name of the driver.
  1877. driver_function    db    2
  1878. parameter_list    label    byte
  1879.     db    1    ;major rev of packet driver
  1880.     db    9    ;minor rev of packet driver
  1881.     db    14    ;length of parameter list
  1882.     db    EADDR_LEN    ;length of MAC-layer address
  1883.     dw    GIANT    ;MTU, including MAC headers
  1884.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  1885.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  1886.     dw    0    ;(# of successive xmits) - 1
  1887. int_num    dw    0    ;Interrupt # to hook for post-EOI
  1888.             ;processing, 0 == none,
  1889.  
  1890.     MakePublic recv_buf_size, recv_buf,    recv_buf_end, recv_buf_head
  1891.     MakePublic recv_buf_tail,end_resident
  1892.  
  1893. recv_buf_size    dw    ser_buf_size,0        ;receive buffer size
  1894. recv_buf    dw    ?        ;->receive buffer
  1895. recv_buf_end    dw    ?        ;->after end of buffer
  1896. recv_buf_head    dw    ?        ;->next character to get
  1897. recv_buf_tail    dw    ?        ;->next character to store
  1898. dummy        dw    1234h
  1899.  
  1900. IP_TYPE    DW    0800H
  1901.  
  1902.   ifdef debug
  1903.     MakePublic Pak_Count, xmit_time
  1904.   endif
  1905. Pak_Count    dw    0        ; semaphore for    packets received
  1906. asyrxint_cnt    dw    0        ; loop counter in ari
  1907.  
  1908.     MakePublic    rcv_modes
  1909. rcv_modes    dw    4        ;number    of receive modes in our table
  1910.         dw    0,0,0,rcv_mode_3
  1911.  
  1912.     MakePublic    as_send_pkt
  1913. ; The Asynchronous Transmit Packet routine.
  1914. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  1915. ;   interrupts possibly enabled.
  1916. ; Exit with nc if ok, or else cy if error, dh set to error number.
  1917. ;   es:di and interrupt enable flag preserved on exit.
  1918. as_send_pkt:
  1919.     ret
  1920.  
  1921.     MakeExternal    delaysub:near
  1922.  
  1923.  
  1924.     MakePublic    drop_pkt
  1925. ; Drop a packet from the queue.
  1926. ; Enter with es:di -> iocb.
  1927. drop_pkt:
  1928.     assume    ds:nothing
  1929.     ret
  1930.  
  1931.     MakePublic    xmit
  1932. ; Process a transmit interrupt with the least possible latency to achieve
  1933. ;   back-to-back packet transmissions.
  1934. ; May only use ax and dx.
  1935. xmit:
  1936.     assume    ds:nothing
  1937.     ret
  1938.  
  1939.  
  1940.     MakePublic    send_pkt
  1941. ;
  1942. ; mod 7/25/89 John Grover
  1943. ; - operates with interrupts on. Xmits one byte per interrupt
  1944. ; - only turns transmitter buffer empty interrupt off when
  1945. ; - all bytes of all packets are transmitted.
  1946.  
  1947. send_pkt:
  1948. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  1949. ;  (only if the high-performance bit is set in driver_function)
  1950.  
  1951. ;enter with ds:si -> packet, cx = packet length.
  1952. ;exit with nc if ok, or else cy if error, dh set to error number.
  1953. ;called from telnet layer via software interrupt
  1954. ; We just send each byte in turn. No UART interrupts are needed nor wanted.
  1955. ; In fact the overdone receiver material omits to note that xmtr interrupts
  1956. ; can be lost while processing rcvr ones. Small benefits are no stalled
  1957. ; programs, no transmitter buffer, no problems at 19200 b/s. Joe Doupnik
  1958.  
  1959.     assume    ds:nothing, es:nothing
  1960.  
  1961.         Show    col_InOut,'O'
  1962.     sti                ; enable interrupts
  1963.     cld
  1964.     mov    al,FR_END        ; Flush out any line garbage
  1965.     call    send_char
  1966.     jc    send_pkt_end        ; c = failure to send
  1967.  
  1968. ;Copy input to output, escaping special characters
  1969. send_pkt_1:
  1970.     lodsb
  1971.     cmp    al,FR_ESC      ; escape FR_ESC with FR_ESC and T_FR_ESC
  1972.     jne    send_pkt_2
  1973.  
  1974.     mov    al,FR_ESC
  1975.     call    send_char
  1976.     jc    send_pkt_end
  1977.  
  1978.     mov    al,T_FR_ESC
  1979.     jmp    short send_pkt_3
  1980.  
  1981. send_pkt_2:
  1982.     cmp    al,FR_END      ; escape FR_END with FR_ESC and T_FR_END
  1983.     jne    send_pkt_3
  1984.  
  1985.     mov    al,FR_ESC
  1986.     call    send_char
  1987.     jc    send_pkt_end
  1988.  
  1989.     mov    al,T_FR_END
  1990.  
  1991. send_pkt_3:
  1992.     call    send_char
  1993.     jc    send_pkt_end
  1994.  
  1995.     loop    send_pkt_1        ; do cx user characters
  1996.  
  1997.     mov    al,FR_END        ; terminate it with a FR_END
  1998.     call    send_char
  1999.     jc    send_pkt_end
  2000.  
  2001.     clc
  2002.  
  2003. send_pkt_end:
  2004.         Show    col_InOut,' '
  2005.     ret
  2006.  
  2007.  
  2008.  
  2009. ;----------------------------------------------------------------------------
  2010. ;----------------------------------------------------------------------------
  2011. ;----------------------------------------------------------------------------
  2012.  
  2013. ;
  2014. ;      our serial driver
  2015. ;
  2016.  
  2017.     MakePublic    ser_funcs
  2018.  
  2019.  
  2020. ser_DTR:
  2021.     mov    al,MCR_RTS or MCR_OUT2
  2022.     or    cx,cx
  2023.         jz    no_DTR
  2024.  
  2025.     or    al,MCR_DTR
  2026.  
  2027. no_DTR:    loadport
  2028.     setport    MCR
  2029.     SlowOut
  2030.     jmp    ser_ret
  2031.  
  2032.  
  2033.     MakeExternal    int_dis:near,DOSPrint:near
  2034.  
  2035. ser_setall:
  2036.     push    ds
  2037.     push    es
  2038.     push    si
  2039.     call    int_dis            ; return old interrupt
  2040.     pop    si
  2041.         pop    ds                      ; source segment
  2042.         push    cs
  2043.         pop     es                      ; dest segment
  2044.         mov    di,offset TheInfo       ; dest offset
  2045.         mov    cx,10            ; data length in words
  2046.         cld
  2047.         rep movsw
  2048.         pop    ds
  2049.         call    set_recv_isr
  2050.         call    etopen            ; reinitialize this new chip
  2051.     jmp    ser_ret
  2052.  
  2053.  
  2054. ser_info:
  2055.     cmp    cx,24
  2056.         jl    nov
  2057.  
  2058.     cld
  2059.         mov     di,si
  2060.         mov     ax,majver
  2061.         stosw
  2062.     mov     ax,TheVersion
  2063.         stosw
  2064.         mov     si,offset TheInfo
  2065.         mov     cx,10                   ; number of words
  2066.         rep movsw
  2067.  
  2068. nov:    jmp    ser_ret
  2069.  
  2070. ser_lines:
  2071.     loadport
  2072.         SetPort    MSR
  2073.         SlowIn
  2074.         shr    ax,4
  2075.         and    ax,000Fh
  2076.         mov    word ptr es:[si],ax
  2077.         jmp    ser_ret
  2078.  
  2079. ser_funcs:
  2080.         cmp    al,1
  2081.         je    ser_avail
  2082.  
  2083.         cmp    al,2
  2084.         je    send_raw
  2085.  
  2086.     cmp    al,3
  2087.     je    get_raw
  2088.  
  2089.         cmp    al,4
  2090.         je    ser_DTR
  2091.  
  2092.         cmp    al,5
  2093.         je    ser_setall
  2094.  
  2095.         cmp    al,6
  2096.         je    ser_info
  2097.  
  2098.         cmp    al,7
  2099.         je    ser_lines
  2100.  
  2101.  
  2102.     stc        ; unknown function code            
  2103.         jmp    ser_x
  2104.  
  2105. ser_ret:
  2106.     clc        ; ok return code
  2107.  
  2108. ser_x:    ret
  2109.  
  2110.  
  2111.  
  2112. ser_avail:
  2113.     call    ser_av
  2114.     jmp    ser_ret    
  2115.  
  2116. ser_av:
  2117.     call    ser_av_reg
  2118.     mov    es:[si],cx
  2119.     ret
  2120.  
  2121. ser_av_reg:
  2122.     mov    cx,recv_buf_tail
  2123.         sub    cx,recv_buf_head
  2124.         jge    ser_av_1        ; positive length
  2125.  
  2126.         add    cx,recv_buf_size    ; negative, add buf size
  2127. ser_av_1:
  2128.     ret
  2129.  
  2130.  
  2131.     assume    ds:code
  2132.  
  2133.  
  2134. get_raw:                     ; read cx chars to es:di
  2135.         push    cs
  2136.         pop    ds            ; ds now points to code seg
  2137.     mov    dx,cx
  2138.         call    ser_av_reg        ; find amount available
  2139.         cmp    dx,cx
  2140.         jle    get_lok
  2141.  
  2142.         mov    dx,cx            ; trim request to avail
  2143.  
  2144. get_lok:
  2145.     mov    cx,dx            ; requested length
  2146.     mov    ax,cx
  2147.     cld
  2148.     stosw                 ; return cx to caller
  2149.     or    cx,cx
  2150.         jle    get_ex            ; requested <= 0 !!
  2151.  
  2152.     mov    si,recv_buf_head
  2153.  
  2154. get_loop:
  2155.     lodsb                ; get byte from buffer
  2156.         stosb                 ; store in user's buffer
  2157.         cmp    si,recv_buf_end
  2158.         jb    get_bot
  2159.  
  2160.         mov    si,recv_buf        ; back to top of buffer
  2161.  
  2162. get_bot:
  2163.         loop    get_loop
  2164.  
  2165.         mov    recv_buf_head,si    ; update head ptr
  2166.  
  2167. get_ex:
  2168.     mov    cx,dx            ; return length read
  2169.     jmp    ser_ret
  2170.  
  2171.     assume    ds:nothing, es:nothing
  2172.  
  2173. ;
  2174. ;  send_raw: send a stream of characters (no interpretation)
  2175. ;
  2176. ;
  2177.  
  2178. send_raw:                  ; send cx chars from ds:si
  2179.     sti                ; enable interrupts
  2180.     cld
  2181.         push    es
  2182.         pop    ds
  2183.         or    cx,cx
  2184.         jle    send_raw_end
  2185.  
  2186.  
  2187. send_raw_1:
  2188.     lodsb
  2189.     call    send_char
  2190.     jc    send_raw_end
  2191.  
  2192.     loop    send_raw_1        ; do cx user characters
  2193.  
  2194.     clc
  2195.  
  2196. send_raw_end:
  2197.     jmp    ser_ret            ; done ok
  2198.  
  2199.  
  2200.  
  2201. ;----------------------------------------------------------------------------
  2202. ;----------------------------------------------------------------------------
  2203. ;----------------------------------------------------------------------------
  2204.  
  2205. ; mod 7/25/89 John Grover
  2206. ; redone by Joe Doupnik, Dec 1991
  2207. ;
  2208. ;
  2209.     assume    ds:nothing, es:nothing
  2210. send_char:                ; send the character in al
  2211.   ifdef grg
  2212.       push    es
  2213.     push    ax
  2214.         mov    ax,0B800h
  2215.         mov    es,ax
  2216.     inc    byte ptr es:[col_chout]
  2217.     pop    ax
  2218.     pop    es
  2219.   endif
  2220.       push    dx
  2221.     push    cx
  2222.     xchg    ah,al            ; put data char into ah
  2223.     xor    cx,cx            ; 64K retry counter
  2224.         mov     bl,hardware_switch      ; Get hardware check (CTS) switch
  2225.  
  2226. outc1:    loadport
  2227.     SetPort    LSR
  2228.     SlowIn
  2229.     test    al,LSR_THRE        ; Transmitter (THRE) ready?
  2230.     jnz    outc2            ; nz = yes
  2231.  
  2232.     loop    outc1
  2233.  
  2234.     stc                ; carry set for failure
  2235.     jmp    short outc3        ; timeout
  2236.  
  2237. outc2:    xor    cx,cx            ; reset retry counter
  2238.     or    bl,bl                   ; Yes -- check CTS ready if needed.
  2239.         jz      outc25            ; No check -- send the character.
  2240.  
  2241.         SetPort    MSR
  2242.     SlowIn
  2243.         test    al,MSR_CTS              ; Is CTS ready?
  2244.         jz    outc1            ; no, go check again
  2245.  
  2246.  
  2247. outc25:    xchg    al,ah            ; now send it
  2248.     mov    dx,io_addr
  2249.     Delay
  2250.     SlowOut                ; send the byte
  2251.     clc                ; status of success
  2252.  
  2253. outc3:    pop    cx
  2254.     pop    dx
  2255.     ret
  2256.  
  2257.  
  2258.  
  2259.     MakePublic    get_address
  2260. get_address:
  2261. ;get the address of the interface.
  2262. ;enter with es:di -> place to get the address, cx = size of address buffer.
  2263. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  2264.     assume    ds:code
  2265.     xor    cx,cx
  2266.     clc
  2267.     ret
  2268.  
  2269.  
  2270.     MakePublic    set_address
  2271. set_address:
  2272. ;set the address of the interface.
  2273. ;enter with es:di -> place to get the address, cx = size of address buffer.
  2274. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  2275.     assume    ds:nothing
  2276.     clc
  2277.     ret
  2278.  
  2279.  
  2280. rcv_mode_3:
  2281. ;receive mode 3 is the only one we support, so we don't have to do anything.
  2282.     ret
  2283.  
  2284.  
  2285.     MakePublic    set_multicast_list
  2286. set_multicast_list:
  2287. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  2288. ;return nc if we set all of them, or cy,dh=error if we didn't.
  2289.     mov    dh,NO_MULTICAST
  2290.     stc
  2291.     ret
  2292.  
  2293.  
  2294.     MakePublic    get_multicast_list
  2295. get_multicast_list:
  2296. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  2297. ;return    cy, NO_ERROR if we don't remember all of the addresses ourselves.
  2298. ;return cy, NO_MULTICAST if we don't implement multicast.
  2299.     mov    dh,NO_MULTICAST
  2300.     stc
  2301.     ret
  2302.  
  2303.  
  2304.     MakePublic    terminate
  2305. terminate:
  2306.     ret
  2307.  
  2308.     MakePublic    reset_interface
  2309. reset_interface:
  2310. ;reset the interface.
  2311.     assume    ds:code
  2312.     ret
  2313.  
  2314.  
  2315. ;called    when we    want to determine what to do with a received packet.
  2316. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  2317.     MakeExternal    recv_find: near
  2318.  
  2319. ;called after we have copied the packet into the buffer.
  2320. ;enter with ds:si ->the packet, cx = length of the packet.
  2321.     MakeExternal    recv_copy: near
  2322.  
  2323.     MakeExternal    count_in_err: near
  2324.     MakeExternal    count_out_err: near
  2325.  
  2326.     MakePublic    recv
  2327.  
  2328. ;
  2329. ; mod 7/25/89 John Grover
  2330. ;
  2331. ;called from the recv isr.  All registers have been saved, and ds=cs.
  2332. ;Upon exit, the interrupt will be acknowledged.
  2333.  
  2334.     assume    ds:code
  2335.  
  2336. recv:
  2337.  
  2338. rci_mo:    loadport
  2339.     setport    IIR
  2340.     SlowIn               ; any interrupts at all?
  2341.     test    al,IIR_IP
  2342.     jne    rci_x            ; no.
  2343.  
  2344.     and    al,IIR_ID
  2345.     cmp    al,IIR_RDA        ; Receiver interrupt
  2346.     je    ari
  2347.  
  2348. rci_ni:    cmp    al,IIR_MSTAT
  2349.     jne    rci_x
  2350.  
  2351.     setport    MSR            ; make sure of CTS status
  2352.     SlowIn
  2353. ;;;;    test    al, MSR_CTS        ; test removed?????
  2354.     jmp    rci_mo
  2355.  
  2356.  
  2357. rci_x:    ret
  2358.  
  2359.  
  2360. ;-------------------------------------------------------------------------
  2361. ;Process 8250 receiver interrupts
  2362. ;
  2363. ; mod 7/25/89 John Grover
  2364. ; - this branches off when bps < 9600. See ari_a.
  2365. ; - Above 9600 bps we go into a loop to process a packet at
  2366. ; - a time. If not data ready for a certain amount of time,
  2367. ; - the process exits and waits for the next byte. This certain
  2368. ; - amount of time to wait depends on the bps and CPU processor speed
  2369. ; - and is determined in the initialization of the driver.
  2370. ; - Upon receiving the FR_END character for the first frame in the
  2371. ; - buffer a semaphore is set which tells rf to run.
  2372.  
  2373. ari:    mov    bx,ds            ; get set up for the routine
  2374.     mov    es,bx
  2375.     mov    bx,xmit_time            ; is zero if no polling desired
  2376.  
  2377. ari_a:    mov    di,recv_buf_tail
  2378.     xor    bp,bp            ; set flag to indicate 1st char processed
  2379.     mov    si,Pak_Count        ; optimization
  2380.     mov    ah,LSR_DR
  2381.  
  2382. ari_again:
  2383.     xor    cx,cx            ; initialize counter
  2384.     loadport
  2385.     setport    LSR
  2386.  
  2387. ari_in:    SlowIn
  2388.     test    al,LSR_OE
  2389.         jz    noovr
  2390.  
  2391.     ShowInc    col_ovrr,'O'
  2392.  
  2393. noovr:    test    al,LSR_FE
  2394.     jz    nofr
  2395.  
  2396.     ShowInc    col_frame,'F'
  2397.  
  2398. nofr:    test    al,ah
  2399.     jnz    ari_gd            ; yes - break out of loop
  2400.  
  2401.        inc    cx            ; no - increase loop counter
  2402.     cmp    cx,bx            ; timeout?
  2403.     jae    ari_ex            ; yes - leave
  2404.  
  2405.     jmp    ari_in            ; no - keep looping
  2406.  
  2407. ;------  got data ready, read the char
  2408.  
  2409. ari_gd:    setport    RBR
  2410.     SlowIn
  2411.  
  2412. ; Process incoming data;
  2413. ; If buffer is full, we have no choice but
  2414. ; to drop the character
  2415.  
  2416.     cmp    di,recv_buf_head
  2417.     jne    ari_ok            ; none - continue
  2418.  
  2419.         ShowInc col_serfull,'S'        ; twiddle screen if buf full
  2420.  
  2421.     or    si,si                   ; maybe - if there are packets
  2422.     jnz    ari_ex            ; yes exit
  2423.  
  2424. ari_ok:    stosb
  2425.     cmp    di,recv_buf_end        ; did we hit the end of the buffer?
  2426.     jne    ari_3            ; no.
  2427.  
  2428.     mov    di,recv_buf        ; yes - wrap around.
  2429.  
  2430. ari_3:    cmp    al,FR_END        ; might    this be    the end of a frame?
  2431.     jne    ari_reset        ; no - reset flag and loop
  2432.  
  2433.     inc    si                      ; yes - indicate packet ready
  2434.     or    bp,bp                   ; was this the first char?
  2435.     jne    ari_ex                  ; no - exit handler
  2436.  
  2437. ari_reset:
  2438.        inc    bp            ; set 1st character flag
  2439.     jmp    ari_again        ; get another character
  2440.  
  2441. ari_ex:    mov    recv_buf_tail,di
  2442.     mov    Pak_Count, si
  2443.  
  2444.         mov     bx,bp
  2445.         add     bl,'0'
  2446.         Show    col_serfull,bl        ; show char gotten count
  2447.         jmp     rci_x
  2448.  
  2449.  
  2450. ; --------------------------------------------------------------
  2451. ;
  2452. ;  recv_exiting
  2453. ;
  2454.     MakePublic    recv_exiting
  2455. recv_exiting:
  2456.     cmp    Pak_Count,0        ; is a packet ready?
  2457.     je    recv_isr_exit           ; no - skip to end
  2458.  
  2459.  
  2460.     push    ax
  2461.     push    bx
  2462.     push    cx
  2463.     push    dx
  2464.     push    ds
  2465.     push    es
  2466.     push    bp
  2467.     push    di
  2468.     push    si
  2469.     push    cs            ; point ds properly
  2470.     pop    ds
  2471.     sti                ; enable interrupts
  2472.  
  2473.     call    rf
  2474.  
  2475.     cli
  2476.     pop    si
  2477.     pop    di
  2478.     pop    bp
  2479.     pop    es
  2480.     pop    ds
  2481.     pop    dx
  2482.     pop    cx
  2483.     pop    bx
  2484.     pop    ax
  2485.  
  2486. recv_isr_exit:
  2487.     ret
  2488.  
  2489.  
  2490. ; --------------------------------------------------------------
  2491. ;
  2492. ;  rf
  2493. ;
  2494. ; mod 7/25/89 John Grover
  2495. ;
  2496. ; - rf now operates with interrupts on. It is triggered
  2497. ; - by the Pak_Count flag and continues until all bytes
  2498. ; - in all packets in the buffer have been transmitted to the upper
  2499. ; - layer.
  2500. ;
  2501.   ifdef debug
  2502.     MakePublic rf
  2503.   endif
  2504.  
  2505. rf:    cmp    Pak_Count, 0        ; should we do this?
  2506.     jle    rf_end            ; no - exit
  2507.  
  2508. rf_0:    mov    si,recv_buf_head    ;process characters.
  2509.     xor    cx,cx            ;count up the size here.
  2510.     cld                ; quite important
  2511.  
  2512. rf_1:    call    recv_char        ;get a char.
  2513.     je    rf_2            ;go if no more chars.
  2514.  
  2515.     cmp    al,FR_ESC        ;an escape?
  2516.     je    rf_1            ;yes - don't count this char.
  2517.  
  2518.     inc    cx            ;no - count this one.
  2519.     jmp    rf_1
  2520.  
  2521. rf_2:    jcxz    rf_3z            ;count zero? yes - free the frame
  2522.  
  2523. ;we don't need to set the type because none are defined for SLIP.
  2524.  
  2525.     push    si            ;save si in case we reject it.
  2526.     push    bx
  2527.     MOV    DI,CS
  2528.     MOV    ES,DI
  2529.     mov    di,0
  2530.     mov    dl,cs:driver_class
  2531.     call    recv_find        ;look up our type.
  2532.     pop    bx
  2533.     pop    si
  2534.  
  2535.     mov    ax,es            ;is this pointer null?
  2536.     or    ax,di
  2537.     je    rf_3            ;yes - just free the frame.
  2538.  
  2539.     push    cx
  2540.     push    es            ;remember where the buffer pointer is
  2541.     push    di
  2542.  
  2543.     mov    si,recv_buf_head    ;process characters.
  2544.  
  2545. rf_4:    call    recv_char
  2546.     je    rf_6            ;yes - we're all done.
  2547.  
  2548.     cmp    al,FR_ESC        ;an escape?
  2549.     jne    rf_5            ;no - just store it.
  2550.  
  2551.     call    recv_char        ;get the next character.
  2552.     je    rf_6
  2553.  
  2554.     cmp    al,T_FR_ESC
  2555.     mov    al,FR_ESC        ;assume T_FR_ESC
  2556.     je    rf_5            ;yup, that's it    - store FR_ESC
  2557.  
  2558.     mov    al,FR_END        ;nope, store FR_END
  2559.  
  2560. rf_5:    stosb                ;store the byte.
  2561.     jmp    rf_4
  2562.  
  2563. rf_6:    mov    recv_buf_head,si    ;we're skipped to the end.
  2564.     pop    si            ;now give the frame to the client.
  2565.     pop    ds
  2566.     pop    cx
  2567.     assume    ds:nothing
  2568.     call    recv_copy        ; do the upcall to the tcp driver
  2569.     push    cs
  2570.     pop    ds
  2571.     assume    ds:code
  2572.     jmp    rf_end
  2573.  
  2574. rf_3:
  2575.     ShowInc col_TCPFull,'T'
  2576.  
  2577. rf_3z:    mov    recv_buf_head,si    ;remember the new starting point.
  2578.  
  2579. rf_end:    dec    Pak_Count
  2580.  
  2581.     cmp    Pak_Count,0        ; are there more packets ready?
  2582.     jbe    rf_9
  2583.  
  2584.     jmp    rf_0                  ; yes - execute again
  2585.  
  2586. rf_9:    ret
  2587.  
  2588.  
  2589. ; --------------------------------------------------------------
  2590. ;
  2591. ;  recv_char
  2592. ;
  2593. ; mod 7/25/89 John Grover
  2594. ; - Now    uses buffer pointers to determine if there are
  2595. ; - characters left.
  2596. ;
  2597.  
  2598. recv_char:
  2599. ;enter with si -> receive buffer, bx = receive count.  Wrap around if needed.
  2600. ;return with nz, al = next char.  Return zr if there are no more chars in
  2601. ;  this frame.
  2602. ;
  2603.     lodsb
  2604.     cmp    si,recv_buf_end
  2605.     jb    recv_char_1
  2606.  
  2607.     mov    si,recv_buf
  2608.  
  2609. recv_char_1:
  2610.     mov    bx, recv_buf_tail
  2611.     cmp    si, bx
  2612.     je    recv_char_2
  2613.  
  2614.     cmp    al,FR_END
  2615.  
  2616. recv_char_2:
  2617.     ret
  2618.  
  2619.  
  2620.  
  2621. set_baud:
  2622. ;compute the divisor given the baud rate.
  2623.  
  2624.     mov    dx,baudclk+2
  2625.     mov    ax,baudclk
  2626.     mov    bx,0
  2627.  
  2628. sb_1:    inc    bx
  2629.     sub    ax,baud_rate
  2630.     sbb    dx,baud_rate+2
  2631.     jnc    sb_1
  2632.  
  2633.     dec    bx
  2634.     add    ax,baud_rate
  2635.     adc    dx,baud_rate+2
  2636.  
  2637. sb_2:    call    flush_chars
  2638.     loadport            ;Purge the receive data buffer
  2639.     mov    ah,LCR_DLAB        ;Turn on divisor latch access bit
  2640.     setport    LCR
  2641.     call    setbit
  2642.  
  2643.     mov    al,bl            ;Load the two bytes of the divisor.
  2644.     setport    DLL
  2645.     SlowOut
  2646.     mov    al,bh
  2647.     setport    DLM
  2648.     SlowOut
  2649.  
  2650.     mov    ah,LCR_DLAB        ;Turn off divisor latch access bit
  2651.     setport    LCR
  2652.     call    clrbit
  2653.     ret
  2654.  
  2655.  
  2656.  
  2657.         
  2658.  
  2659. flush_chars:
  2660.     loadport            ;Purge the receive data buffer
  2661.     mov    cx,1000            ;flush up to 1K chars
  2662.  
  2663. flush_next:
  2664.     SlowIn
  2665.     test    al,LSR_DR
  2666.     jz    flush_done        ; yes - break out of loop
  2667.  
  2668.     setport    RBR
  2669.     SlowIn                 ; read and ignore the char
  2670.     loop    flush_next
  2671.  
  2672. flush_done:
  2673.     ret
  2674.  
  2675.  
  2676.  
  2677. ; --------------------------------------------------------------
  2678. ;
  2679. ;  etopen
  2680. ;
  2681. ; mod 7/25/89 John Grover
  2682. ; - Contains a loop to determine a pseudo timeout for ari.
  2683. ; - The value is determined by transmitting characters in a
  2684. ; - loop whose clock cycles are nearly the same as the "sister"
  2685. ; - loop in ari. The per character, maximum time used
  2686. ; - basis which is then multiplied by a factor to achieve a timeout
  2687. ; - value for the particular bps and CPU speed of the host.
  2688.  
  2689.     MakePublic    etopen
  2690. etopen:
  2691.     pushf
  2692.     cli
  2693. ;
  2694. ; mod  3/16/90  Denis DeLaRoca
  2695. ; - determine if 16550 uart is present
  2696. ; - if so initialize fifo buffering
  2697. ;
  2698.     loadport
  2699.     setport    FCR
  2700.     mov    al,FIFO_ENABLE
  2701.     SlowOut                ;outportb(base+FCR,(char) FIFO_ENABLE)
  2702.     setport    IIR
  2703.     SlowIn                ;inportb(base+IIR)
  2704.     and    al,IIR_FIFO_ENABLED     ;     & IIR_FIFO_ENABLED
  2705.     cmp    al,IIR_FIFO_ENABLED    ;both bits must be on   NEW, 11/20/90
  2706.     jnz    not_16550               ;nope, we don't have 16550 chip
  2707.  
  2708.     mov    is_16550,1              ;yes, note fact
  2709.     mov    al,FIFO_SETUP           ;and setup FIFO
  2710.     setport    FCR
  2711.     SlowOut                ;outportb(base+FCR,(char) FIFO_SETUP)
  2712.  
  2713. not_16550:
  2714.     call    flush_chars
  2715.  
  2716. ;Set line control register: 8 bits, no parity
  2717.     loadport
  2718.     mov    al,ser_misc
  2719.  
  2720.     setport    LCR
  2721.     SlowOut
  2722.  
  2723. ;Turn on receive interrupt enable in 8250, leave transmit
  2724. ; and modem status interrupts turned off for now
  2725.     mov    al,IER_DAV
  2726.     setport    IER
  2727.     SlowOut
  2728.  
  2729. ; Set modem control register: assert DTR, RTS, turn on 8250
  2730. ; master interrupt enable (connected to OUT2)
  2731.  
  2732.     mov    al,MCR_DTR or MCR_RTS or MCR_OUT2
  2733.     setport    MCR
  2734.     SlowOut
  2735.  
  2736.     call    set_baud
  2737.     call    set_recv_isr        ;Set interrupt vector to SIO handler
  2738.  
  2739. ;set up the various pointers.
  2740.     mov    dx,offset end_resident
  2741.  
  2742.     mov    recv_buf,dx
  2743.     mov    recv_buf_head,dx
  2744.     mov    recv_buf_tail,dx
  2745.     add    dx,recv_buf_size
  2746.     mov    recv_buf_end,dx
  2747.  
  2748.         xor    si,si
  2749.     cmp    baud_rate,9600        ; below 19200 we're strictly
  2750.     jbe    t_a                  ; interrupt driven
  2751.  
  2752.  
  2753.     ; the following code attempts to determine a pseudo timeout
  2754.     ; value    to use in the loop that waits for an incoming character
  2755.     ; in ari. The value returned in xmit_time is the number of
  2756.     ; loops processed between characters - therefore the loop used below
  2757.     ; is and should    remain similar to the loop used in ari.
  2758.  
  2759.     mov    ah,LSR_THRE
  2760.     mov    cx,16            ; take the highest of 16 runs
  2761.     xor    si,si            ; will hold highest value
  2762.  
  2763. xmit_time_start:
  2764.     xor    di,di            ; initialize counter
  2765.     loadport
  2766.     setport    THR            ; xmit a character
  2767.         mov    al,' '            ; send a space to minimize damage
  2768.     SlowOut
  2769.     setport    LSR               ; set up    to check for an empty buffer
  2770.  
  2771. ; next is the loop actually being timed
  2772.  
  2773.     mov    bx,1            ; wait up to 65K times
  2774.  
  2775. xmit_time_top:
  2776.     SlowIn
  2777.     test    al,ah
  2778.     jnz    xmit_time_done
  2779.  
  2780.     inc    di
  2781.     cmp    cx,cx            ; these next few instructions do nothing
  2782.     jmp    xmit_time_1        ; except maintain similarity with the
  2783.                     ; "sister" loop in ari
  2784. xmit_time_1:
  2785.     inc    bx
  2786.     jmp    xmit_time_top
  2787.  
  2788. xmit_time_done:                ; end of timed loop
  2789.  
  2790.     cmp    si,di            ; compare highest value with new value
  2791.     ja    xmit_time_end        ; no bigger - just loop
  2792.     mov    si,di            ; bigger - save it
  2793.  
  2794. xmit_time_end:
  2795.     loop    xmit_time_start        ; bottom of outer loop
  2796.  
  2797.     call    flush_chars        ; throw away any echoed zeroes
  2798.  
  2799.     shl    si,3            ; we'll wait 8 characters worth
  2800.  
  2801. t_a:    mov    xmit_time,si        ; retain largest value
  2802.     mov    al, int_no        ; Get board's interrupt vector
  2803.     add    al, 8
  2804.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  2805.     jb    set_int_num        ; No.
  2806.  
  2807.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  2808.  
  2809. set_int_num:
  2810.     xor    ah, ah            ; Clear high byte
  2811.     mov    int_num, ax        ; Set parameter_list int num.
  2812.  
  2813.     popf
  2814.     clc                ;indicate no errors.
  2815.     ret
  2816.  
  2817.  
  2818. ;Set bit(s) in I/O port
  2819. setbit:
  2820. ;enter with dx = port, ah = bit to set.
  2821.     SlowIn
  2822.     or    al,ah
  2823.     SlowOut
  2824.     ret
  2825.  
  2826.  
  2827. ;Clear bit(s) in I/O port
  2828. clrbit:
  2829. ;enter with dx = port, ah = bit to set.
  2830.     SlowIn
  2831.     not    al            ;perform an and-not using DeMorgan's.
  2832.     or    al,ah
  2833.     not    al
  2834.     SlowOut
  2835.     ret
  2836.  
  2837. is_nochip_msg:    db    'Serial Port is not there??',CR,LF,'$'
  2838.  
  2839.  
  2840. ;**************************************************************************
  2841. ;**************************************************************************
  2842. ;**************************************************************************
  2843. ;any code after this will not be kept after initialization.
  2844.  
  2845. end_resident    label    byte
  2846.  
  2847. ;**************************************************************************
  2848. ;**************************************************************************
  2849. ;**************************************************************************
  2850.  
  2851.     MakePublic    usage_msg
  2852. usage_msg    db    "usage: UMSLIP [?] [-n] [-w] [-s] [packet_int_no]"
  2853.         db    " [recv_buf_size]",CR,LF,'$'
  2854.  
  2855.     MakePublic    copyright_msg
  2856. copyright_msg    db    "Packet driver for SLIP, version ",'0'+majver mod 10
  2857.         db    ".",'0'+TheVersion mod 10,CR,LF
  2858.         db    "Portions Copyright 1988 Phil Karn,"
  2859.         db    " 1991 Joe Doupnik,",CR,LF
  2860.         db    "Portions Copyright 1993 Univ. of Minnesota",cr,lf,'$'
  2861.  
  2862.  
  2863.     MakeExternal    set_recv_isr: near
  2864.  
  2865. ;enter with si -> argument string, di -> word to store.
  2866. ;if there is no number, don't change the number.
  2867.     MakeExternal    get_number: near
  2868.  
  2869. ;enter with dx -> name of word, di -> dword to print.
  2870.     MakeExternal    print_number: near
  2871.     MakeExternal    print_number_dec: near
  2872.     MakeExternal    print_number_hex: near
  2873.     MakeExternal    print_crlf: near
  2874.  
  2875. ;enter with si -> argument string.
  2876. ;skip spaces and tabs.  Exit with si -> first non-blank char.
  2877.     MakeExternal    skip_blanks: near
  2878.  
  2879.  
  2880.     MakePublic    parse_args
  2881.  
  2882. parse_args:
  2883.     mov    di,offset recv_buf_size
  2884.     call    get_number
  2885.     clc
  2886.     ret
  2887.  
  2888.  
  2889. code    ends
  2890.  
  2891. ;   PC/FTP Packet Driver source, conforming to version 1.05 of the spec
  2892. ;   Updated to version 1.08 Feb. 17, 1989.
  2893. ;   Copyright 1988-1992 Russell Nelson
  2894.  
  2895. ;   This program is free software; you can redistribute it and/or modify
  2896. ;   it under the terms of the GNU General MakePublic License as published by
  2897. ;   the Free Software Foundation, version 1.
  2898. ;
  2899. ;   This program is distributed in the hope that it will be useful,
  2900. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  2901. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  2902. ;   GNU General MakePublic License for more details.
  2903. ;
  2904. ;   You should have received a copy of the GNU General MakePublic License
  2905. ;   along with this program; if not, write to the Free Software
  2906. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  2907.  
  2908. code    segment word
  2909.     assume    cs:code, ds:code
  2910.  
  2911.     MakeExternal    phd_dioa: byte
  2912.     MakeExternal    phd_environ: word
  2913.     MakeExternal    flagbyte: byte,quiet:byte,end_resident:near,recv_buf_size:word
  2914.  
  2915. ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
  2916.  
  2917.     MakePublic    print_number_hex
  2918. print_number_hex:
  2919.     Print
  2920.     mov    al,'0'
  2921.     call    chrout
  2922.     mov    al,'x'
  2923.     call    chrout
  2924.     mov    ax,[di]            ;print the number in hex.
  2925.     mov    dx,[di+2]
  2926.     call    dwordout
  2927.     ret
  2928.  
  2929.  
  2930.  
  2931.     MakePublic    print_number_dec
  2932.  
  2933. print_number_dec:
  2934.     or    dx,dx
  2935.         je    NoTxt
  2936.  
  2937.     Print
  2938.  
  2939. NoTxt:    mov    ax,[di]            ;print the number in decimal.
  2940.     mov    dx,[di+2]
  2941.     call    decout
  2942.     ret
  2943.  
  2944.     MakePublic    print_crlf
  2945. print_crlf:
  2946.     mov    al,CR
  2947.     call    chrout
  2948.     mov    al,LF
  2949.     call    chrout
  2950.         ret
  2951.  
  2952.  
  2953.     MakePublic    print_number
  2954. print_number:
  2955. ;enter with dx -> dollar terminated name of number, di ->dword.
  2956. ;exit with the number printed and the cursor advanced to the next line.
  2957.  
  2958.     call    print_number_hex
  2959.     mov    al,' '
  2960.     call    chrout
  2961.     mov    al,'('
  2962.     call    chrout
  2963.         mov    dx,0
  2964.     call    print_number_dec
  2965.     mov    al,')'
  2966.     call    chrout
  2967.     call    print_crlf
  2968.     ret
  2969.  
  2970.  
  2971. ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
  2972.  
  2973.     MakePublic    decout
  2974. decout:
  2975.     mov    si,ax            ;get the number where we want it.
  2976.     mov    di,dx
  2977.     or    ax,dx            ;is the number zero?
  2978.     jne    decout_nonzero
  2979.     mov    al,'0'            ;yes - easier to just print it, than
  2980.     jmp    chrout            ;  to eliminate all but the last zero.
  2981. decout_nonzero:
  2982.  
  2983.     xor    ax,ax            ;start with all zeroes in al,bx,bp
  2984.     mov    bx,ax
  2985.     mov    bp,ax
  2986.  
  2987.     mov    cx,32            ;32 bits in two 16 bit registers.
  2988. decout_1:
  2989.     shl    si,1
  2990.     rcl    di,1
  2991.     xchg    bp,ax
  2992.     call    addbit
  2993.     xchg    bp,ax
  2994.     xchg    bx,ax
  2995.     call    addbit
  2996.     xchg    bx,ax
  2997.     adc    al,al
  2998.     daa
  2999.     loop    decout_1
  3000.  
  3001.     mov    cl,'0'            ;prepare to eliminate leading zeroes.
  3002.     call    byteout            ;output the first two.
  3003.     mov    ax,bx            ;output the next four
  3004.     call    wordout            ;output the next four
  3005.     mov    ax,bp
  3006.     jmp    wordout
  3007.  
  3008. addbit:    adc    al,al
  3009.     daa
  3010.     xchg    al,ah
  3011.     adc    al,al
  3012.     daa
  3013.     xchg    al,ah
  3014.     ret
  3015.  
  3016. ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
  3017.  
  3018.     MakePublic    dwordout, wordout, byteout, digout
  3019. dwordout:
  3020.     mov    cl,'0'            ;prepare to eliminate leading zeroes.
  3021.     xchg    ax,dx            ;just output 32 bits in hex.
  3022.     call    wordout            ;output dx.
  3023.     xchg    ax,dx
  3024. wordout:
  3025.     push    ax
  3026.     mov    al,ah
  3027.     call    byteout
  3028.     pop    ax
  3029. byteout:
  3030.     mov    ah,al
  3031.     shr    al,1
  3032.     shr    al,1
  3033.     shr    al,1
  3034.     shr    al,1
  3035.     call    digout
  3036.     mov    al,ah
  3037.  
  3038. digout:
  3039.     and    al,0fh
  3040.     add    al,90h    ;binary digit to ascii hex digit.
  3041.     daa
  3042.     adc    al,40h
  3043.     daa
  3044.     cmp    al,cl            ;leading zero?
  3045.     je    digout_1
  3046.     mov    cl,-1            ;no more leading zeros.
  3047.     jmp    chrout
  3048.  
  3049. digout_1:
  3050.     ret
  3051. ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
  3052.  
  3053.     MakePublic    chrout
  3054. chrout:
  3055.     push    ax            ;print the char in al.
  3056.     push    dx
  3057.     mov    dl,al
  3058.     test    quiet,1
  3059.     jnz    nochout
  3060.  
  3061.     mov    ah,2
  3062.     int    21h
  3063.  
  3064. nochout:
  3065.     pop    dx
  3066.     pop    ax
  3067.     ret
  3068.  
  3069.  
  3070. ;*************************************************************************
  3071.  
  3072. ;usage_msg is of the form "usage: driver [-d -n] <packet_int_no> <args>"
  3073.     MakeExternal    usage_msg: byte
  3074.  
  3075. ;copyright_msg is of the form:
  3076. ;"Packet driver for the foobar",CR,LF
  3077. ;"Portions Copyright 19xx, J. Random Hacker".
  3078.     MakeExternal    copyright_msg: byte
  3079.  
  3080. copyleft_msg    label    byte
  3081.  db "Packet driver skeleton copyright 1988-92, Crynwr Software.",CR,LF
  3082.  db "This program is free software; see the file COPYING for details.",CR,LF
  3083.  db "NO WARRANTY; see the file COPYING for details."
  3084. crlf_msg    db    CR,LF,'$'
  3085.  
  3086. no_resident_msg    label    byte
  3087.  db CR,LF,"*** Packet driver failed to initialize the board ***",CR,LF,'$'
  3088.  
  3089. ;parse_args should parse the arguments.
  3090. ;called with ds:si -> immediately after the packet_int_no.
  3091.     MakeExternal    parse_args: near
  3092.  
  3093. ;print_parameters should print the arguments.
  3094.     MakeExternal    print_parameters: near
  3095.  
  3096.     MakeExternal    our_isr: near, their_isr: dword
  3097.     MakeExternal    ser_their_isr: dword
  3098.     MakeExternal    packet_int_no: byte
  3099.     MakeExternal    is_at: byte, sys_features: byte
  3100.     MakeExternal    int_no: byte
  3101.     MakeExternal    driver_class: byte
  3102.  
  3103.  
  3104. packet_int_no_name    db    "Packet interrupt number ",'$'
  3105. eaddr_msg    db    "My Ethernet address is ",'$'
  3106. aaddr_msg    db    "My ARCnet address is ",'$'
  3107.  
  3108. already_msg    db    CR,LF,"There is already a packet driver at ",'$'
  3109. int_msg        db    CR,LF
  3110.         db    "Error: <int_no> should be between 0 and "
  3111. int_msg_num    label    word
  3112.         db    "15 inclusive", '$'
  3113.  
  3114. our_address    db    EADDR_LEN dup(?)
  3115.     MakePublic    etopen_diagn
  3116. etopen_diagn    db    0        ; errorlevel from etopen if set
  3117.  
  3118. ;etopen should initialize the device.  If it needs to give an error, it
  3119. ;can issue the error message and quit to dos.
  3120.     MakeExternal    etopen: near
  3121.  
  3122. ;get the address of the interface.
  3123. ;enter with es:di -> place to get the address, cx = size of address buffer.
  3124. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  3125.     MakeExternal    get_address: near
  3126.  
  3127. already_error:
  3128.     mov    quiet,0
  3129.     mov    dx,offset already_msg
  3130.     mov    di,offset packet_int_no
  3131.     call    print_number
  3132.     mov    ax,4c05h        ; give errorlevel 5
  3133.     int    21h
  3134.  
  3135. usage_error:
  3136.     mov    dx,offset usage_msg
  3137.  
  3138.     MakePublic    error
  3139. error:
  3140.     mov    quiet,0
  3141.     Print
  3142.     mov    ax,4c0ah        ; give errorlevel 10
  3143.     int    21h
  3144.  
  3145.     MakePublic    start_1
  3146. start_1:
  3147.     cld
  3148.  
  3149. ;
  3150. ; Get the feature byte (if reliable) so we can know if it is a microchannel
  3151. ; computer and how many interrupts there are.
  3152. ;
  3153.     mov    ah,0c0h
  3154.     int    15h            ; es:bx <- sys features block
  3155.     jc    look_in_ROM        ; error, must use rom.
  3156.     or    ah,ah
  3157.     jnz    look_in_ROM
  3158.     mov    dx,es:[bx]        ; # of feature bytes
  3159.     cmp    dx,4            ; do we have the feature byte we want?
  3160.     jae    got_features        ;yes.
  3161. look_in_ROM:
  3162.     mov    dx,0f000h        ;ROM segment
  3163.     mov    es,dx
  3164.     cmp    byte ptr es:[0fffeh],0fch;is this an AT?
  3165.     jne    identified        ;no.
  3166.     or    sys_features,TWO_8259    ; ATs have 2nd 8259
  3167.     jmp    identified        ; assume no microchannel
  3168. got_features:
  3169.     mov    ah,es:[bx+2]        ; model byte
  3170.     cmp    ah,0fch
  3171.     je    at_ps2
  3172.     ja    identified        ; FD, FE and FF are not ATs
  3173.     cmp    ah,0f8h
  3174.     je    at_ps2
  3175.     ja    identified        ; F9, FA and FB are not ATs
  3176.     cmp    ah,09ah
  3177.     jbe    identified        ; old non-AT Compacs go here
  3178.  
  3179. at_ps2:                    ; 9B - F8 and FC are assumed to
  3180.     mov    ah,es:[bx+5]        ;   have reliable feature byte
  3181.     mov    sys_features,ah
  3182.  
  3183. identified:
  3184.     mov    si,offset phd_dioa+1
  3185.     call    skip_blanks        ;end of line?
  3186.     cmp    al,CR
  3187.     je    nopknum            ; yes, assume 0x60
  3188.  
  3189. chk_options:
  3190.     call    skip_blanks
  3191.     cmp    al,'-'            ; any options?
  3192.     jne    no_more_opt
  3193.  
  3194.     inc    si            ; skip past option char
  3195.     lodsb                ; read next char
  3196.     or    al,20h            ; convert to lower case
  3197.     cmp    al,'n'
  3198.     jne    not_n_opt
  3199.     or    flagbyte,N_OPTION
  3200.     jmp    chk_options
  3201.  
  3202. not_n_opt:
  3203.     cmp    al,'w'
  3204.     jne    not_w_opt
  3205.  
  3206.     or    flagbyte,W_OPTION
  3207.     jmp    chk_options
  3208.  
  3209. not_w_opt:
  3210.     cmp    al,'s'
  3211.         jne    usage_error_j_1
  3212.  
  3213.     mov    quiet,1
  3214.         jmp    chk_options
  3215.  
  3216.  
  3217. usage_error_j_1:
  3218.     jmp    usage_error
  3219.  
  3220.  
  3221. no_more_opt:
  3222.     cmp    al,'?'
  3223.         je    usage_error_j_1
  3224.  
  3225.     mov    di,offset packet_int_no    ;parse the packet interrupt number
  3226.     mov    bx,offset packet_int_no_name
  3227.     call    get_number        ;  for them.
  3228.  
  3229.     call    parse_args
  3230.     jc    usage_error_j_1
  3231.  
  3232.     call    skip_blanks        ;end of line?
  3233.     cmp    al,CR
  3234.     jne    usage_error_j_1
  3235.  
  3236. nopknum:
  3237.     call    verify_packet_int
  3238.     jnc    packet_int_ok
  3239.     jmp    error
  3240.  
  3241. packet_int_ok:
  3242.     jne    packet_int_unused
  3243.     jmp    already_error        ;give an error if there's one there.
  3244. packet_int_unused:
  3245.  
  3246. ;
  3247. ; Verify that the interrupt number they gave is valid.
  3248. ;
  3249.     cmp    int_no,15        ;can't possibly be > 15.
  3250.     ja    int_bad
  3251.     test    sys_features,TWO_8259    ; 2nd 8259 ?
  3252.     jnz    int_ok            ;yes, no need to check for <= 7.
  3253.     mov    int_msg_num,'7'+' '*256    ;correct the error message, just in case.
  3254.     cmp    int_no,7        ;make sure that the packet interrupt
  3255.     jbe    int_ok            ;  number is in range.
  3256. int_bad:
  3257.     mov    dx,offset int_msg
  3258.     jmp    error
  3259. int_ok:
  3260.  
  3261. ;
  3262. ; Map IRQ 2 to IRQ 9 if needed.
  3263. ;
  3264.     test    sys_features,TWO_8259    ; 2nd 8259 ?
  3265.     je    no_mapping_needed    ;no, no mapping needed
  3266.     cmp    int_no,2        ;map IRQ 2 to IRQ 9.
  3267.     jne    no_mapping_needed
  3268.     mov    int_no,9
  3269.  
  3270. no_mapping_needed:
  3271.  
  3272.     mov    dx,offset copyright_msg
  3273.     Print
  3274.     mov    dx,offset copyleft_msg
  3275.     Print
  3276.  
  3277.     call    take_packet_int
  3278.  
  3279.     mov    ah,49h            ;free our environment, because
  3280.     mov    es,phd_environ        ;  we won't need it.
  3281.     int    21h
  3282.  
  3283.     mov    bx,1            ;get the stdout handle.
  3284.     mov    ah,3eh            ;close it in case they redirected it.
  3285.     int    21h
  3286.  
  3287.     mov    dx,offset end_resident
  3288.     add    dx,recv_buf_size
  3289.     add    dx,0fh            ;round up to next highest paragraph.
  3290.     mov    cl,4
  3291.     shr    dx,cl
  3292.     mov    ah,31h            ;terminate, stay resident.
  3293.     mov    al,etopen_diagn        ; errorlevel (0 - 9, just diagnostics)
  3294.     int    21h
  3295.  
  3296.  
  3297.  
  3298.  
  3299. no_resident:
  3300.     mov    dx,offset no_resident_msg
  3301.     Print
  3302.  
  3303.     mov    ax,4c00h + 32        ; give errorlevel 32
  3304.     cmp    al,etopen_diagn
  3305.     ja    no_et_diagn        ; etopen gave specific reason?
  3306.     mov    al,etopen_diagn        ; yes, use that for error level
  3307. no_et_diagn:
  3308.     int    21h
  3309.  
  3310. ;             Suggested errorlevels:
  3311. ;
  3312. ; _____________________  0 = normal
  3313. ;              1 = unsuitable memory address given; corrected
  3314. ; In most cases every-     2 = unsuitable IRQ level given; corrected
  3315. ; thing should work as     3 = unsuitable DMA channel given; corrected
  3316. ; expected for lev 1-5     4 = unsuitable IO addr given; corrected (only 1 card)
  3317. ; _____________________     5 = packet driver for this int # already loaded
  3318. ; External errors, when    20 = general cable failure (but pkt driver is loaded)
  3319. ; corrected normal    21 = network cable is open             -"-
  3320. ; operation starts    22 = network cable is shorted          -"-
  3321. ; _____________________ 23 = 
  3322. ; Packet driver not    30 = usage message
  3323. ; loaded. A new load    31 = arguments out of range
  3324. ; attempt must be done    32 = unspecified device initialization error
  3325. ;            33 = 
  3326. ;            34 = suggested memory already occupied
  3327. ;            35 = suggested IRQ already occupied
  3328. ;            36 = suggested DMA channel already occupied
  3329. ;            37 = could not find the network card at this IO address
  3330.  
  3331.  
  3332. take_packet_int:
  3333.     mov    ah,35h            ;remember their packet interrupt.
  3334.     mov    al,packet_int_no
  3335.     int    21h
  3336.     mov    their_isr.offs,bx
  3337.     mov    their_isr.segm,es
  3338.  
  3339.     mov    ah,25h            ;install our packet interrupt
  3340.     mov    dx,offset our_isr
  3341.     int    21h
  3342.  
  3343.         ret
  3344.  
  3345.  
  3346.     MakePublic    DOSPrint
  3347.  
  3348. DOSPrint:
  3349.     test    quiet,1
  3350.         jnz    NoPrint
  3351.  
  3352.         mov    ah,9
  3353.         int    21h
  3354.  
  3355. NoPrint:
  3356.     ret
  3357.  
  3358.  
  3359. signature    db    'PKT DRVR',0
  3360. signature_len    equ    $-signature
  3361.  
  3362. packet_int_msg    db    CR,LF
  3363.         db    "Error: <packet_int_no> should be in the range 0x60 to 0x80"
  3364.         db    '$'
  3365.  
  3366. verify_packet_int:
  3367. ;enter with no special registers.
  3368. ;exit with cy,dx-> error message if the packet int was bad,
  3369. ;  or nc,zr,es:bx -> current interrupt if there is a packet driver there.
  3370. ;  or nc,nz,es:bx -> current interrupt if there is no packet driver there.
  3371.     cmp    packet_int_no,60h    ;make sure that the packet interrupt
  3372.     jb    verify_packet_int_bad    ;  number is in range.
  3373.     cmp    packet_int_no,80h
  3374.     jbe    verify_packet_int_ok
  3375. verify_packet_int_bad:
  3376.     mov    dx,offset packet_int_msg
  3377.     stc
  3378.     ret
  3379. verify_packet_int_ok:
  3380.  
  3381.     mov    ah,35h            ;get their packet interrupt.
  3382.     mov    al,packet_int_no
  3383.     int    21h
  3384.  
  3385.     lea    di,3[bx]        ;see if there is already a signature
  3386.     mov    si,offset signature    ;  there.
  3387.     mov    cx,signature_len
  3388.     repe    cmpsb
  3389.     clc
  3390.     ret
  3391. ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
  3392.  
  3393.     MakePublic    get_number
  3394. get_number:
  3395.     mov    bp,10            ;we default to 10.
  3396.     jmp    short get_number_0
  3397.  
  3398.     MakePublic    get_hex
  3399. get_hex:
  3400.     mov    bp,16
  3401. ;get a hex number, skipping leading blanks.
  3402. ;enter with si->string of digits,
  3403. ;    di -> dword to store the number in.  [di] is not modified if no
  3404. ;        digits are given, so it acts as the default.
  3405. ;return cy if there are no digits at all.
  3406. ;return nc, bx:cx = number, and store bx:cx at [di].
  3407. get_number_0:
  3408.     call    skip_blanks
  3409.     call    get_digit        ;is there really a number here?
  3410.     jc    get_number_3
  3411.  
  3412.     xor    ah,ah
  3413.     cmp    ax,bp            ;larger than our base?
  3414.     jae    get_number_3        ;yes.
  3415.  
  3416.     or    al,al            ;Does the number begin with zero?
  3417.     jne    get_number_4        ;no.
  3418.     mov    bp,8            ;yes - they want octal.
  3419. get_number_4:
  3420.  
  3421.     xor    cx,cx            ;get a hex number.
  3422.     xor    bx,bx
  3423. get_number_1:
  3424.     lodsb
  3425.     cmp    al,'x'            ;did they really want hex?
  3426.     je    get_number_5        ;yes.
  3427.     cmp    al,'X'            ;did they really want hex?
  3428.     je    get_number_5        ;yes.
  3429.     call    get_digit        ;convert a character into an int.
  3430.     jc    get_number_2        ;not a digit (neither hex nor dec).
  3431.     xor    ah,ah
  3432.     cmp    ax,bp            ;larger than our base?
  3433.     jae    get_number_2        ;yes.
  3434.  
  3435.     push    ax            ;save the new digit.
  3436.  
  3437.     mov    ax,bp            ;multiply the low word by ten.
  3438.     mul    cx
  3439.     mov    cx,ax            ;keep the low word.
  3440.     push    dx            ;save the high word for later.
  3441.     mov    ax,bp
  3442.     mul    bx
  3443.     mov    bx,ax            ;we keep only the low word (which is our high word)
  3444.     pop    dx
  3445.     add    bx,dx            ;add the high result from earlier.
  3446.  
  3447.     pop    ax            ;get the new digit back.
  3448.     add    cx,ax            ;add the new digit in.
  3449.     adc    bx,0
  3450.     jmp    get_number_1
  3451.  
  3452. get_number_5:
  3453.     mov    bp,16            ;change the base to hex.
  3454.     jmp    get_number_1
  3455.  
  3456. get_number_2:
  3457.     dec    si
  3458.     mov    [di],cx            ;store the parsed number.
  3459.     mov    [di+2],bx
  3460.     clc
  3461.     jmp    short get_number_6
  3462.  
  3463. get_number_3:
  3464.     cmp    al,'?'            ;did they ask for the default?
  3465.     stc
  3466.     jne    get_number_6        ;no, return cy.
  3467.  
  3468.     add    si,1            ;skip past the question mark.
  3469.     clc
  3470.  
  3471. get_number_6:
  3472.     ret
  3473.  
  3474.  
  3475. ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
  3476.  
  3477.     MakePublic    get_digit
  3478. get_digit:
  3479. ;enter with al = character
  3480. ;return nc, al=digit, or cy if not a digit.
  3481.     cmp    al,'0'            ;decimal digit?
  3482.     jb    get_digit_1        ;no.
  3483.     cmp    al,'9'            ;. .?
  3484.     ja    get_digit_2        ;no.
  3485.     sub    al,'0'
  3486.     clc
  3487.     ret
  3488. get_digit_2:
  3489.     cmp    al,'a'            ;hex digit?
  3490.     jb    get_digit_3
  3491.     cmp    al,'f'            ;hex digit?
  3492.     ja    get_digit_3
  3493.     sub    al,'a'-10
  3494.     clc
  3495.     ret
  3496. get_digit_3:
  3497.     cmp    al,'A'            ;hex digit?
  3498.     jb    get_digit_1
  3499.     cmp    al,'F'            ;hex digit?
  3500.     ja    get_digit_1
  3501.     sub    al,'A'-10
  3502.     clc
  3503.     ret
  3504. get_digit_1:
  3505.     stc
  3506.     ret
  3507.  
  3508.  
  3509. ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
  3510.  
  3511.     MakePublic    skip_blanks
  3512. skip_blanks:
  3513.     lodsb                ;skip blanks.
  3514.     cmp    al,' '
  3515.     je    skip_blanks
  3516.     cmp    al,HT
  3517.     je    skip_blanks
  3518.     dec    si
  3519.     ret
  3520.  
  3521.  
  3522.  
  3523.     MakePublic    print_ether_addr
  3524.  
  3525.  
  3526. print_ether_addr:
  3527.     mov    cx,EADDR_LEN
  3528.  
  3529. print_ether_addr_0:
  3530.     push    cx
  3531.     lodsb
  3532.     mov    cl,' '            ;Don't eliminate leading zeroes.
  3533.     call    byteout
  3534.     pop    cx
  3535.     cmp    cx,1
  3536.     je    print_ether_addr_1
  3537.  
  3538.     mov    al,':'
  3539.     call    chrout
  3540.  
  3541. print_ether_addr_1:
  3542.     loop    print_ether_addr_0
  3543.     ret
  3544.  
  3545. code    ends
  3546.  
  3547.     end     start
  3548.